Files
httpclient/docs/adr/ADR-002-request-id-propagation.md

51 lines
2.2 KiB
Markdown
Raw Permalink Normal View History

# ADR-002: Request ID Propagation via X-Request-ID Header
**Status:** Accepted
**Date:** 2026-03-18
## Context
In a distributed system, a single inbound request may fan out to multiple downstream service
calls. Without a shared correlation identifier, tracing a request across service logs requires
matching timestamps or other heuristics. A request ID, propagated as an HTTP header
(`X-Request-ID`), lets logs across services be correlated by a single value.
The `logz` module owns the request ID context key (ADR-003 global: context helpers live with
data owners). `httpclient` depends on `logz` and should use its helpers rather than define its
own context key.
## Decision
Inside the retry function in `Do`, before executing each request attempt, the client reads
the request ID from the context using `logz.GetRequestID(req.Context())`. If a non-empty
value is present, it is set as the `X-Request-ID` header on the outgoing request:
```go
if id := logz.GetRequestID(req.Context()); id != "" {
req.Header.Set("X-Request-ID", id)
}
```
The header is set on every retry attempt, not just the first, because the same `*http.Request`
object is reused across retries.
If no request ID is present in the context (the ID is the zero string), the header is not
set. This is verified by `TestClient_Do_NoRequestID`.
## Consequences
**Positive:**
- Request IDs flow automatically to downstream services without any caller boilerplate.
- Correlation across service boundaries works with no additional middleware.
- The integration is testable: `TestClient_Do_InjectsRequestID` verifies end-to-end
propagation using `logz.WithRequestID` and an `httptest.Server`.
**Negative:**
- `httpclient` takes a direct import dependency on `logz`. This is accepted per ADR-001
(global) which permits direct imports between framework modules.
- The header name `X-Request-ID` is hardcoded. Projects that use a different header name
(e.g. `X-Correlation-ID`) cannot configure this without forking the client.
- Header propagation only works when the caller places the request ID in the context via
`logz.WithRequestID`. Requests built without a context carrying a request ID will not
have the header set.