In this lesson, you will learn how to maintain visibility into your system by propagating trace context across asynchronous message boundaries using headers.
When a request travels through an HTTP API, tracing tools like Jaeger or Honeycomb automatically attach a trace-id to the request headers. However, when that request triggers a background task—like sending an email or processing a video—the flow is broken the moment the message hits a queue. Because the task worker runs in a separate process or container, it loses the context of the original user request.
To visualize the entire lifecycle of a task, you must manually inject the current trace context into the message headers before publishing to your broker (like RabbitMQ or Redis). When your worker pulls the message, it extracts these headers to resume the trace.
Example: Propagating Context
In a standard Node.js producer, you can attach trace data to the headers property of the message:
const message = { taskId: '123' };
const traceHeaders = {
'x-trace-id': currentTraceContext.traceId,
'x-span-id': currentTraceContext.spanId
};
// Publishing the message with context
channel.publish('tasks', 'process-job', Buffer.from(JSON.stringify(message)), {
headers: traceHeaders
});
On the consumer side, your worker needs to intercept the message, extract these headers, and inform your telemetry SDK that it is continuing an existing span:
channel.consume('tasks', (msg) => {
const { 'x-trace-id': traceId } = msg.properties.headers;
// Start a new span as a child of the original trace
tracer.startSpan('process-job', { childOf: traceId });
// ... process task ...
});
By linking these spans, you bridge the gap between the producer and the consumer. This allows you to see the exact moment a message was enqueued, how long it waited in the queue, and how long the worker took to process it—transforming a "black box" into a clear, end-to-end timeline.
Key Takeaway: By injecting trace identifiers into message headers at the producer and extracting them at the consumer, you enable end-to-end visibility across your asynchronous task pipelines.