Prompt and use cases
An HTTP request publishes a message for asynchronous processing. How do you propagate Trace Context safely across retries, batches, and tenants? This prompt fits backend, observability, and messaging interviews. The goal is causal correlation across execution boundaries without treating request context as permanent authorization or business data.
What interviewers assess
- Whether you understand the boundaries of
traceparent, optionaltracestate, and propagators. - Whether producer, message-processing, and retry spans have clear parent relationships.
- Whether you handle batched messages, delayed consumption, dead letters, sampling, and expiry.
- Whether you prevent sensitive baggage, cross-tenant data, and forged trust signals from spreading.
Questions to clarify before answering
Confirm the transport, message durability, batching and retry behavior, and whether consumers cross services or trust domains. Clarify whether the desired relationship is for one business operation, one message, or a batch. Ask about sampling, retention, tenant isolation, and whether external producers may inject context. Finally, define dead-letter handling and whether manual replay creates a new trace branch.
30-second answer framework
“The entry service extracts and validates propagation headers, then injects minimal trace context when publishing. The consumer extracts it, creates an independent consumer span, and represents retries, batches, and dead letters explicitly. Across trust domains I accept only controlled fields and drop sensitive baggage; platform policy governs sampling and expiry, while replay uses a new trace ID linked to the original.”
Step-by-step deep answer
- Define boundaries: Model HTTP ingress, message publication, transport, and consumption as separate execution units with explicit inject and extract owners.
- Choose a carrier: Put the standard propagation format in message headers or controlled metadata; never copy the full request, identity token, or arbitrary baggage into durable messages.
- Model spans: The publisher creates a producer span and the consumer creates a consumer span; for batches, record message links instead of pretending the batch is one request.
- Handle retries and dead letters: Give each attempt its own span and attempt attribute while preserving the original event link; dead-letter handling and replay create a new branch.
- Govern security: Restrict cross-domain injection, sanitize user-controlled fields, isolate tenant labels, and cap sampling, retention, and context size.
High-quality sample answer
I would separate standard context, business correlation, and security boundaries. The HTTP entry point extracts only well-formed propagation headers, validates version and length, and creates a server span. When publishing, the producer span injects minimal trace context into message metadata while an immutable business event ID is stored separately because the two have different purposes. The consumer extracts metadata and creates a consumer span; each downstream operation gets its own child span. A batch is not forced under the first message as one parent: I record a batch span and bounded message links. Every retry adds an attempt and backoff attribute while preserving the event ID. Once a message enters a dead-letter queue, manual replay creates a new trace linked to the original so the new execution cannot masquerade as history. Baggage from another tenant or external producer is dropped by default; only platform-approved low-sensitivity fields cross the boundary. I would validate context size, extraction failures, message-to-consumer correlation, retry visibility, and cross-tenant leakage with tests and production metrics.
Common mistakes
- Treating a trace ID as an authentication credential or business idempotency key.
- Persisting full HTTP headers, user input, or tokens in a durable message.
- Putting batch consumption and all retries under one span, distorting timing.
- Reusing the old trace during dead-letter replay, hiding the new attempt.
- Discussing SDK calls without trust domains, sampling, retention, and size governance.
Follow-up questions and responses
A message is retried ten times. How many spans should exist?
Create a distinguishable span for each actual processing attempt and link it with the attempt number, event ID, and original producer operation. This exposes per-attempt latency without reporting ten executions as one.
How do you choose a parent for a batch?
Create a consumer span for the batch, then use bounded links or child spans for messages that need analysis. Do not arbitrarily choose the first message as the batch parent; retain batch-level statistics and correlation IDs when sampling is limited.
May an external customer inject tracestate?
Accept protocol-conformant fields only as untrusted input. Across a trust boundary, limit length, keys, and forwarding, remove sensitive or high-cardinality fields, and never use them for authorization.
How does manual dead-letter replay stay traceable?
Create a new trace and execution span for replay, recording the original message ID, operator, reason, and replay batch. Link old and new traces through a controlled relation while preserving the immutable original failure.