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)
- Generated at request entry by BFF middleware as UUID v4 (so1-004).
- Attached to Hono request context.
- Logged on every log line (
requestIdfield in structured JSON). - Propagated to outbound calls as
X-Request-Id: {requestId}. - Returned in every response —
X-Request-Idheader on success,requestIdfield in the error envelope. - 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
requestIdto 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
- FNP Observability & Prometheus Metrics monitoring FNP systems
- ProtocolMessage Envelope adding a new wire message type
- purr-api Layered Architecture adding a new feature to purr-api