dcontext-dactor
Automatic dcontext propagation through dactor actor messages.
When actors send messages to each other — locally or across the network —
distributed context (request IDs, tenant info, feature flags, etc.) needs to
travel with those messages. dcontext-dactor makes this transparent by
providing inbound and outbound interceptors that handle serialization,
deserialization, and scope restoration automatically.
Quick Start
[]
= "0.8"
= "0.8"
= "0.3.1"
use async_ctx;
use ;
// Register interceptors with your dactor runtime
runtime.add_outbound_interceptor;
runtime.add_inbound_interceptor;
// That's it! Context now flows automatically between actors.
// Inside any async actor handler:
let rid = .unwrap;
How It Works
Two-Stage Pipeline
The crate uses a two-stage pipeline that separates header normalization from context restoration:
Sender Receiver
────── ────────
OutboundInterceptor InboundInterceptor
├─ local target? Stage 1: on_receive()
│ └─ attach ContextSnapshot ├─ wire header? deserialize → snapshot
└─ remote target? └─ normalize to ContextSnapshotHeader
└─ serialize → ContextHeader Stage 2: wrap_handler()
(includes scope chain) ├─ enter named scope "remote:<actor_name>"
└─ wrap future with dcontext::async_ctx::with_context()
Outbound — The ContextOutboundInterceptor captures the current context
and attaches it to the message headers. For local targets, it uses a
zero-copy snapshot (preserving local-only values). For remote targets, it
serializes to wire bytes.
Inbound — The ContextInboundInterceptor works in two stages:
on_receivenormalizes incoming headers (deserializes wire bytes into a snapshot)wrap_handlerruns the handler future insidedcontext::async_ctx::with_context(), so context is automatically available inside the handler — no manual restoration needed.
Local vs Remote Propagation
| Scenario | Header Type | Serialization | Local-only values |
|---|---|---|---|
| Same process | ContextSnapshotHeader |
None | ✅ Preserved |
| Cross-network | ContextHeader |
Bincode bytes | ❌ Excluded |
Error Handling
Both interceptors accept an ErrorPolicy:
use ;
// Log warnings and continue (default) — messages are delivered even if
// context serialization/deserialization fails
let outbound = default;
let inbound = default;
// Reject — message is dropped if context cannot be propagated
let outbound = new;
let inbound = new;
Wire Transport Registration
If your actors communicate over the network, register the context header
deserializer with dactor's HeaderRegistry:
use register_context_headers;
let mut header_registry = new;
register_context_headers;
// Pass header_registry to your dactor transport configuration
Manually Extracting Context
If you need the propagated context snapshot for spawning sub-tasks or other
manual use, use extract_context:
use async_ctx;
use extract_context;
async
Full Example
See samples/src/bin/dactor_propagation.rs
for a complete working example.
Scope Chain Integration
The inbound interceptor's wrap_handler automatically creates a named scope
remote:<actor_name> for each inbound message. This makes distributed call
boundaries visible in the scope chain:
// Caller (sync code shown here) sets up context and sends a message:
let _guard = enter_named_scope;
actor_ref.send.await;
// Inside the receiving actor handler (async):
let chain = scope_chain;
// chain == ["api-gateway", "remote:OrderActor"]
This gives you a full distributed call path without manual instrumentation. The scope chain propagates through serialization (wire format v2), so the chain accumulates as requests traverse multiple services and actors.
API Reference
| Type | Purpose |
|---|---|
ContextOutboundInterceptor |
Captures context on message send |
ContextInboundInterceptor |
Restores context on message receive (two-stage) |
ContextHeader |
Serialized wire header ("dcontext.wire") |
ContextSnapshotHeader |
Local snapshot header ("dcontext.snapshot") |
ErrorPolicy |
LogAndContinue (default) or Reject |
extract_context() |
Manually extract propagated context |
register_context_headers() |
Register wire deserializer with HeaderRegistry |
Related
- dcontext — Core context propagation library
- dcontext-tracing — Tracing span integration
- Usage Guide
License
MIT