Message Context¶
MessageContext provides correlation and causation tracking across message handling. When the bus
dispatches a message, it wraps it in a MessageEnvelope and sets a ContextVar-based
MessageContext available to handlers and pipeline behaviors. This enables tracing a chain of
related messages back to the original trigger — essential for logging, auditing, and debugging
distributed operations.
Accessing Context in Handlers¶
Call get_message_context() to retrieve the current context inside any handler or behavior:
Warning
get_message_context() raises RuntimeError if called outside a bus operation. Use
try_get_message_context() when the call site may run outside message handling — see
Optional Access below.
Context Fields¶
| Field | Type | Description |
|---|---|---|
message_id |
UUID |
Unique ID of the current message |
correlation_id |
UUID |
Shared across a chain of related messages |
causation_id |
UUID |
ID of the message that caused this one |
headers |
Mapping[str, str] |
Arbitrary metadata attached to the message |
For a top-level message (no outer context), correlation_id is a fresh UUID and causation_id
equals message_id. When a handler dispatches a nested message, the bus propagates the
correlation and sets the causation — see Correlation Propagation.
Correlation Propagation¶
When a handler invokes another message (nested dispatch), the bus automatically:
- Preserves the outer
correlation_idon the inner message. - Sets the inner
causation_idto the outermessage_id.
This creates a traceable chain from the root message through every message it spawned.
sequenceDiagram
participant Caller
participant Bus as MessageBus
participant H1 as Handler A
participant H2 as Handler B
Caller->>Bus: invoke(RequestA)
Note over Bus: message_id=M1<br/>correlation_id=C1<br/>causation_id=M1
Bus->>H1: handle(RequestA)
H1->>Bus: invoke(RequestB)
Note over Bus: message_id=M2<br/>correlation_id=C1<br/>causation_id=M1
Bus->>H2: handle(RequestB)
H2-->>Bus: response
Bus-->>H1: response
H1-->>Bus: response
Bus-->>Caller: response
Both messages share correlation_id=C1, so you can query all log entries for a single
end-to-end operation regardless of how many messages were involved.
Optional Access¶
try_get_message_context() returns None when no bus operation is active instead of raising.
Use it in code that runs both inside and outside message handling:
DI Injection¶
MessageContext is registered as a transient provider by MessagingModule, resolved via
get_message_context(). You can inject it into pipeline behaviors where the context is already
active:
Warning
Constructor injection works because transient resolves get_message_context() at injection
time. For handlers, prefer calling get_message_context() directly inside handle() — this
is always safe regardless of when the handler instance is created.
Further reading¶
- Message Bus — setup, interfaces, and dispatch methods
- Requests — commands, queries, and request handlers
- Pipeline Behaviors — cross-cutting middleware for request handling