pub trait OutboxStore: Send + Sync {
// Required methods
async fn enqueue(
&self,
messages: &[OutboxMessage],
) -> Result<(), EngineError>;
async fn pending(
&self,
limit: usize,
now: OffsetDateTime,
) -> Result<Vec<OutboxMessage>, EngineError>;
async fn acknowledge(&self, id: OutboxMessageId) -> Result<(), EngineError>;
async fn reschedule(
&self,
id: OutboxMessageId,
deliver_after: OffsetDateTime,
) -> Result<(), EngineError>;
async fn len(&self) -> Result<usize, EngineError>;
// Provided methods
async fn pending_now(
&self,
limit: usize,
) -> Result<Vec<OutboxMessage>, EngineError> { ... }
async fn is_empty(&self) -> Result<bool, EngineError> { ... }
}Expand description
Storage contract for outbox messages.
§Atomicity requirement
In production deployments, calls to OutboxStore::enqueue MUST be
atomic with the corresponding EventStore::append — both writes MUST
succeed or both MUST fail. Implement this by sharing the same database
transaction across both operations.
§Delivery worker contract
The delivery worker loop should:
- Call
OutboxStore::pending_nowto retrieve ready messages. - Attempt delivery to the AS4 endpoint.
- On success: call
OutboxStore::acknowledgeto remove the message. - On transient failure: call
OutboxStore::reschedulewith an exponential back-off delay.
§Blanket Arc implementation
Arc<S> implements OutboxStore whenever S: OutboxStore, so you can
share a store across a delivery worker and command handlers without
additional wrapper types.
Required Methods§
Sourceasync fn enqueue(&self, messages: &[OutboxMessage]) -> Result<(), EngineError>
async fn enqueue(&self, messages: &[OutboxMessage]) -> Result<(), EngineError>
Persist messages durably, ready for delivery.
In a persistent backend this MUST be called within the same transaction as the event append.
§Errors
Returns EngineError::Outbox on storage failure.
Sourceasync fn pending(
&self,
limit: usize,
now: OffsetDateTime,
) -> Result<Vec<OutboxMessage>, EngineError>
async fn pending( &self, limit: usize, now: OffsetDateTime, ) -> Result<Vec<OutboxMessage>, EngineError>
Return up to limit messages ready for delivery as of now.
A message is ready when deliver_after is None or <= now.
Results are ordered oldest-first by created_at.
§Errors
Returns EngineError::Outbox on storage failure.
Sourceasync fn acknowledge(&self, id: OutboxMessageId) -> Result<(), EngineError>
async fn acknowledge(&self, id: OutboxMessageId) -> Result<(), EngineError>
Remove a message from the outbox after successful delivery.
Calling this with an unknown id is a no-op.
§Errors
Returns EngineError::Outbox on storage failure.
Sourceasync fn reschedule(
&self,
id: OutboxMessageId,
deliver_after: OffsetDateTime,
) -> Result<(), EngineError>
async fn reschedule( &self, id: OutboxMessageId, deliver_after: OffsetDateTime, ) -> Result<(), EngineError>
Reschedule a message for a future delivery attempt.
Implementations MUST increment attempt_count on the stored record.
Calling this with an unknown id is a no-op.
§Errors
Returns EngineError::Outbox on storage failure.
Sourceasync fn len(&self) -> Result<usize, EngineError>
async fn len(&self) -> Result<usize, EngineError>
Return the total number of messages currently in the outbox.
§Errors
Returns EngineError::Outbox on storage failure.
Provided Methods§
Sourceasync fn pending_now(
&self,
limit: usize,
) -> Result<Vec<OutboxMessage>, EngineError>
async fn pending_now( &self, limit: usize, ) -> Result<Vec<OutboxMessage>, EngineError>
Return up to limit messages ready for delivery right now.
Convenience wrapper around OutboxStore::pending that uses
OffsetDateTime::now_utc() as the reference time.
§Errors
Returns EngineError::Outbox on storage failure.
Sourceasync fn is_empty(&self) -> Result<bool, EngineError>
async fn is_empty(&self) -> Result<bool, EngineError>
Return true when the outbox contains no messages.
§Errors
Returns EngineError::Outbox on storage failure.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".