Course contents
On this page
Lesson 36 of 59

Commit the order and remember to notify shipping

Use an outbox to cross the gap between a database transaction and message delivery.

The shop commits an order, then sends a message to a shipping program. It crashes between those steps. The order exists, but shipping never hears about it. Sending the message first creates the opposite risk: shipping might act on an order whose transaction later fails.

A local database transaction does not automatically include another program’s state. We need to record the obligation to notify shipping together with the order itself.

Store the notification as data

An outbox is a table of messages waiting to be delivered. In one local transaction, the shop creates order 501 and outbox event E501 saying that the order is ready for shipping.

  1. Commit locally

    Order 501 and outbox event E501 become visible together.

  2. Publisher reads the outbox

    A separate worker sends E501 to shipping.

  3. Record delivery progress

    After receiving confirmation, the publisher marks the event delivered or advances its durable progress.

A crash before publication leaves a durable obligation to retry. Delivery is still a separate step.

The publisher is ordinary application work, so it can also crash. Suppose shipping accepts E501, but the publisher crashes before recording that fact. On restart, E501 still appears pending and is sent again.

The outbox therefore does not imply one delivery attempt. Its value is that an accepted local order does not lose the obligation to publish merely because the process stops between two calls.

Make the receiver tolerate repetition

Give the event a stable identity. A shipping service can record that E501 has already been processed and avoid creating a second shipment for it. The processing marker and the shipping-state change must themselves be coordinated, for example in the receiver’s transaction.

If the receiver marks the event processed before recording the shipment, a crash can lose the action. If it records the shipment and marks processing later, a crash can permit a duplicate. The same atomicity reasoning appears on both sides.

External physical actions, such as a carrier actually collecting a parcel, need their own workflow and reconciliation. A database row cannot make every outside effect transactional.

Stop before the original commit

The order insert succeeds inside the transaction, but inserting E501 fails and the transaction rolls back. Should a later publisher send a shipping message for that attempt?

Read only the committed obligation

No. The transaction accepted neither the order nor its outbox event. The publisher should operate on committed outbox state. If it could send tentative events before commit, the design would again expose shipping to an order that never became real.

This pattern connects local engine guarantees to a wider application without pretending that a successful commit completes the entire workflow.

Debezium’s outbox documentation describes event identities and a concrete publishing integration. The publisher above is a conceptual design, not a requirement to install that tool.

Extended reference

The extended chapter preserves the original technical coverage, additional examples, and citations. The explanation above supplies the concepts needed for this page; the reference develops the specialist cases.

Find a section from the original chapter