Expand description
Outbox pattern for reliable at-least-once outbound message delivery.
§Why the outbox?
When a process transition generates an outbound EDIFACT message (e.g. an APERAK acknowledgement), two writes must happen atomically:
- Domain events are appended to the event store.
- The EDIFACT payload is queued for delivery to the AS4 endpoint.
Without the outbox, a crash between steps 1 and 2 silently loses the outbound message. With the outbox, both writes are part of the same database transaction — a background delivery worker then delivers pending messages, surviving crashes and transient AS4 failures transparently.
§Usage
ⓘ
// After a command dispatch that should trigger an outbound APERAK:
let env = &aperak_envelopes[0];
let msg = OutboxMessage::new(
process.stream_id().clone(),
env.process_id,
env.tenant_id,
env.correlation_id,
env.conversation_id,
env.event_id,
"APERAK",
&recipient_gln,
aperak_payload_json,
);
outbox_store.enqueue(&[msg]).await?;
// Background delivery worker:
let pending = outbox_store.pending_now(50).await?;
for msg in pending {
as4_client.send(&msg).await?;
outbox_store.acknowledge(msg.message_id).await?;
}§Atomicity contract
[InMemoryOutboxStore] does not guarantee transactional atomicity
with InMemoryEventStore. Persistent backend crates
(mako-event-store-slatedb, mako-event-store-postgres) MUST enqueue
messages in the same database transaction as the event append.
Structs§
- Noop
Outbox Store - An
OutboxStorethat silently discards all messages. - Outbox
Message - An outbound message queued for delivery via AS4 or another channel.
- Pending
Outbox - A lightweight outbox message specification produced by
Workflow::handle.
Traits§
- Outbox
Store - Storage contract for outbox messages.
Functions§
- outbox_
idempotency_ key - Compute a deterministic idempotency key for an outbound message.