EVT-6Recommended
Send side effects through an outbox
When a change must also send an email, a webhook or a message, write that task to a table in the same transaction. Send it afterwards from that table.
How to do it
Insert the task into an outbox table inside the transaction. A worker claims due tasks with FOR UPDATE SKIP LOCKED, sends them, marks them sent, and retries failures with backoff. Then a rollback never sends a message, and a crash never loses one. A crash after sending but before marking can send twice, so give each task an ID the receiver uses to drop duplicates.
Examples
SQL example
CREATE TABLE outbox (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
kind text NOT NULL,
payload jsonb NOT NULL,
attempts int NOT NULL DEFAULT 0,
send_after timestamptz NOT NULL DEFAULT now(),
sent_at timestamptz
);
-- Worker, inside its own short transaction
SELECT id, kind, payload FROM outbox
WHERE sent_at IS NULL AND send_after <= now()
ORDER BY id LIMIT 10
FOR UPDATE SKIP LOCKED;
How to check
Kill the process right after commit. On restart, the pending email is sent. Run two workers at once, and no task is sent by both.
Sources
Related rules
- ARC-76 Change one aggregate per transaction in Clean code and architecture
- ARC-81 Holding a lock while waiting on the network in Clean code and architecture
- ARC-91 Run a change across services as a saga with undo steps in Clean code and architecture
- DAT-81 Retry transactions that fail on a conflict in Data and databases
- EML-67 Send each message once in Email
- TKO-16 Give each table one writer during the move in Codebase takeover
- USG-2 Meter on the server after the work succeeds in Usage-based billing
- ECM-6 Keep one writer for each stock count in E-commerce and fulfilment
- EVT-7 Read changes from the database log in Integration and events
- EVT-10 Deliver events through a shared channel in Integration and events
- EVT-16 Move slow work out of the request in Integration and events
- ANA-3 Record business facts on the server in Product analytics and experiments
- SRH-7 Keep search indexes in step with their source in Search
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/events/publishing-events/outbox">Agent Wranglers integration and events playbook</a>. In code you write, add a comment next to it with the same link.