Expand description
§dcontext-dactor
Automatic dcontext propagation through dactor actor messages.
This crate bridges dcontext (distributed context propagation) with
dactor (actor framework) by providing interceptors that automatically
carry context across actor message boundaries — no boilerplate needed
in handlers.
§How It Works
Context propagation is a two-stage interceptor pipeline:
-
Outbound interceptor (sender side) —
ContextOutboundInterceptorcaptures the current dcontext and attaches it as message headers.- Local targets →
ContextSnapshotHeader(preserves local-only values) - Remote targets →
ContextHeader(serialized wire bytes)
- Local targets →
-
Inbound interceptor (receiver side) —
ContextInboundInterceptorperforms two actions:on_receive: normalizes headers — deserializes wire bytes into aContextSnapshotHeaderif needed.wrap_handler: wraps the handler future withdcontext::async_ctx::with_context, restoring the propagated snapshot into the async task-local scope automatically.
This uses dactor 0.3’s wrap_handler feature to wrap the handler future
with a task-local context scope. dcontext::async_ctx::get_context /
dcontext::async_ctx::set_context work transparently inside the handler.
§Error Handling
Both interceptors accept an ErrorPolicy that controls behavior when
serialization or deserialization fails:
ErrorPolicy::LogAndContinue(default) — log a warning, deliver the message without context.ErrorPolicy::Reject— reject the message viaDisposition::Reject.
§Local vs. Remote
-
Local (same process): Context is propagated via
ContextSnapshot, preserving local-only values that cannot be serialized. No serialization is performed. -
Remote (cross-process): Context is serialized to bytes via
dcontext::async_ctx::serialize_contextand transmitted as a wire header. Local-only values are excluded.
§Quick Start
use dcontext_dactor::{ContextOutboundInterceptor, ContextInboundInterceptor};
// Register interceptors on your runtime — that's it!
runtime.add_outbound_interceptor(Box::new(ContextOutboundInterceptor::default()));
runtime.add_inbound_interceptor(Box::new(ContextInboundInterceptor::default()));
// Handlers automatically have dcontext available — no boilerplate
#[async_trait]
impl Handler<MyMessage> for MyActor {
async fn handle(&mut self, msg: MyMessage, ctx: &mut ActorContext) -> () {
// dcontext is automatically restored by the interceptor's wrap_handler
let rid: RequestId = dcontext::async_ctx::get_context("request_id").unwrap();
// ... handle message with context available ...
}
}§Manual Extraction
For advanced use cases (e.g., spawning sub-tasks that need context),
extract_context is still available to pull the snapshot from headers.
with_propagated_context is retained for backward compatibility but is
no longer needed when using the interceptor pipeline.
Structs§
- Context
Header - Header carrying serialized context bytes for wire transport.
- Context
Inbound Interceptor - Inbound interceptor that propagates dcontext automatically through actor message handlers.
- Context
Outbound Interceptor - Outbound interceptor that captures the current dcontext and attaches it to outgoing actor messages as headers.
- Context
Snapshot Header - Header carrying a
ContextSnapshotfor in-process (local) propagation.
Enums§
- Error
Policy - Controls how interceptors behave when serialization or deserialization fails.
Functions§
- extract_
context - Extract the propagated context snapshot from actor message headers.
- register_
context_ headers - Register dcontext header deserializers with a dactor
HeaderRegistry. - with_
propagated_ context Deprecated - Run an async handler body with the propagated dcontext from actor headers.