Delivery-local state
Pass bounded typed data from middleware to guards and handlers within one delivery.
The delivery-local map carries data between stages while one message is processed. A policy result or audit context computed by middleware can be reused by the handler. The map lives with that delivery’s scope and is not shared between messages.
Insert first, extract later#
The complete guard example inserts DeliveryAudit in before_delivery. This snippet belongs inside that middleware callback; exchange is the QueueDeliveryExchange supplied by the framework.
let event_id = exchange.context().event_id().into_inner().to_string();
exchange.insert_local(DeliveryAudit { event_id })?;A handler parameter Local(audit): Local<DeliveryAudit> receives an owned clone. Put parts extractors before the payload. Local<T> requires T: Clone + Send + Sync + 'static; use Local<Arc<T>> for large immutable values to keep cloning inexpensive.
Required and optional values#
| Extractor | When absent |
|---|---|
Local<DeliveryAudit> |
Retryable QUEUE_DELIVERY_LOCAL_MISSING |
Option<Local<DeliveryAudit>> |
None |
A missing required local usually calls for checking the producing middleware’s registration and order. Do not make it optional merely to suppress an error; optional is appropriate when absence is normal in the application contract. Option<E> is not a general mechanism for swallowing extractor errors.
Bounds and type identity#
The map holds at most 32 distinct Rust types. Inserting the same type again returns the previous value and does not consume another slot. Use distinct types such as TenantKey(String) and AuditLabel(String) instead of using String for two meanings. The bound limits type count; your application must bound each stored value’s byte size.
The exchange supports reading, inserting and removing typed locals. A local is not a DI registration and is not automatically resolved through Service<T>. It does not replace a shared replica cache, durable idempotency record or database transaction.
Preserve the trust boundary#
A tenant value taken from a user-controlled header is not a verified principal. Verify the required signature or credentials and tenant relationship first, then put the verified state into a distinct local type. Typed transport does not itself prove validation. A guard should evaluate permission using that explicit contract.
Sources for this page v0.1.0
This guide is based on the reviewed framework commit.