contextvars
), this automatic propagation does not extend across process boundaries or when work is explicitly dispatched to new, independent execution contexts.
The SGP backend no longer expects spans to arrive in-order. This means there is a chance that child spans may become orphans if their respective parent span fails to send.
Understanding Context Propagation
When using context managers (with tracing.create_span(...)
), the SDK automatically sets the current span and trace in a context-local variable. However, when you:
- Spawn a new Python process (e.g., using
multiprocessing
). - Enqueue a task to a background job queue (e.g., Celery, RQ).
- Dispatch work to a separate thread pool where contextvars might not propagate by default (though
threading
typically handles this better thanmultiprocessing
).
trace_id
or parent_id
from the originating process. You must explicitly pass this context.
Strategies for Distributed Tracing
One Trace Per Worker (Simplest)
For parallel work where strict hierarchical linking of every operation across workers isn’t necessary, the easiest approach is to create an independent trace for each worker or process. You can then use agroup_id
to logically link these independent traces together, allowing you to see all related activity in the Traces page, even if they don’t form a single, continuous trace hierarchy. This is ideal for scenarios where workers process independent units of work concurrently.
Extending a Trace Across Workers
If you need to maintain a single, continuous trace hierarchy where operations performed in separate workers are direct children of a span in the main process (or another worker), you must manually propagate the tracing context. This involves:- Retrieving the
group_id
,trace_id
andspan_id
of the parent span in the originating process. - Passing these IDs to the new worker/process (e.g., as function arguments or message queue payload fields).
- Using these explicit IDs when creating new spans in the worker, ensuring they are correctly linked as children.
Scope
object directly in your worker process as this scope may well be shared across jobs leading to incorrect tracing and leaking of tracing data.
Example: Passing Context via Function Arguments
Important Considerations
- Worker Initialization: Each independent Python process (e.g., a new
multiprocessing.Process
) will have its own tracing queue manager. Ensuretracing.init()
is called within each worker’s entry point if you expect it to send tracing data. This typically means callingtracing.init()
at the start of the function that the worker executes. - Error Handling: In distributed systems, be diligent with error handling and ensure spans are ended correctly, even if an exception occurs. Context managers (
with tracing.create_span(...)
) handle this automatically within their scope.