CRUMB a card from devarno-cloud

RequestId Propagation & Tracing

so1 intermediate 4 min read

ELI5

Every request gets a wristband stamped at the door. Every photo, log line, and outbound errand quotes the same wristband number, so a single id stitches together the entire trip.

Technical Deep Dive

Lifecycle (ADR-004)

  1. Generated at request entry by BFF middleware as UUID v4 (so1-004).
  2. Attached to Hono request context.
  3. Logged on every log line (requestId field in structured JSON).
  4. Propagated to outbound calls as X-Request-Id: {requestId}.
  5. Returned in every response — X-Request-Id header on success, requestId field in the error envelope.
  6. Traced: OTEL trace id == requestId, so the same value lights up logs and distributed traces.

Cross-System Trace

sequenceDiagram
participant B as Browser
participant N as so1-rover
participant H as BFF
participant U as GitHub
B->>N: GET /catalog
N->>H: GET /api/catalog (Authorization: Bearer …)
H->>H: gen requestId=abc123, ctx.set
H->>H: log {requestId:abc123, method:GET, path:/api/catalog}
H->>U: GET /repos (X-Request-Id: abc123)
U-->>H: 200
H-->>N: 200 (X-Request-Id: abc123)
N-->>B: 200 (X-Request-Id: abc123)

Log Line Schema

Per ADR-004, every BFF request emits at least:

{
"timestamp": "...",
"requestId": "...",
"method": "GET",
"path": "/api/catalog",
"status": 200,
"duration_ms": 45,
"userId": "user_123",
"orgId": "org_456",
"error": null
}

On failure the error field carries { code, message, details } mirroring the envelope (so1-010).

Why UUID v4

Random, non-sequential, low collision probability, no central authority — fits a stateless BFF deployed across many instances (so1-014).

Key Terms

  • X-Request-Id → the wire header carrying the id outbound and back.
  • Trace id → OTEL’s global identifier; in so1, set equal to requestId to avoid double-bookkeeping.
  • Structured logging → log records as JSON objects rather than printf strings.

Q&A

Q: A user pastes a requestId into a support ticket — what can engineers find? A: The exact log line (with userId, orgId, path, status, duration, error code), the upstream API trace (via X-Request-Id), and the originating Job (via metadata.requestId if applicable — so1-007).

Q: Where is the requestId attached to a Job? A: In metadata.requestId — copied from the create request’s id (so1-007).

Q: Does the browser ever see the requestId before a failure? A: Yes — every successful response carries X-Request-Id (ADR-004); error responses carry it in the body envelope as well.

Examples

A 502 from /api/bff/workflows: rover’s ApiError includes requestId: "abc123". The error boundary shows it in the UI; an engineer greps the BFF log for "abc123" and instantly finds the BFF line plus the upstream n8n response in details.upstream.

neighbors on the map