Implementation of transactional outbox pattern, a method that allows to atomically perform a local business transaction and send domain events to a message broker. The example leverages
- NodeJS as services runtime.
- Debezium as CDC platform.
- RabbitMQ as events broker.
- PostgreSQL as services data store.
The implementation consists of an order service acting as the events producer. It stores events in an outbox table and performs regular business operations as part of the same database transaction. Debezium monitors the outbox table while streaming new entries to RabbitMQ. The shipment service acts as a message consumer reading events from the broker.
High level architecture mirrors the schema below.
The only requirement to run the example locally is Docker. Once you have Docker installed on your local machine, all services can be started by running
$ docker compose up --build
The repository also includes a Taskfile that aliases some commands. In case you'd like to bootstrap all services by using Task tool you can run
$ task bootstrap
Data folder includes some static data that can be used as body of http requests. To create a new order you can perform the following http request against order service APIs
// Using cURL.
$ curl -X POST -H "Content-Type: application/json" --data @./resources/data/create-order-request.json http://localhost:3000/orders
// Using Task runner.
$ task create-order
To cancel an order line that was previously created you can run
// Using cURL.
// Be sure to replace `:orderID` and `:orderLineId` with the actual values.
$ curl -X PUT -H "Content-Type: application/json" --data @./resources/data/cancel-order-line-request.json http://localhost:3000/orders/:orderID/lines/:orderLineId
// Using Task runner.
// Be sure to provide the actual values to `ORDER_ID` and `ORDER_LINE_ID` env vars.
$ task cancel-order-line ORDER_ID="replace-me" ORDER_LINE_ID="replace-me"
Following services logs you should be able to get some insights on what's happening under the hood while interacting with public APIs. Since both order_service
and shipment_service
run in debug mode, all SQL queries performed against the data store will be part of stdout stream.
// order-service logs.
$ docker compose logs --follow order-service
// order-service logs with Task runner.
$ task order-service-logs
// shipment-service logs.
$ docker compose logs --follow shipment-service
// shipment-service logs with Task runner.
$ task shipment-service-logs
To start an interactive session against order database and run queries you can do the following:
// Interactive session using docker compose.
$ docker compose run --rm order-db psql -d postgres://postgres:postgres@order-db/orderdb
// Interactive session using Task runner.
$ task order-db-cli
// Run queries.
$ select * from orders.purchase_order;
What's depicted right above closely applies to shipment database:
// Interactive session using docker compose.
$ docker compose run --rm shipment-db psql -d postgres://postgres:postgres@shipment-db/shipmentdb
// Interactive session using Task runner.
$ task shipment-db-cli
// Run queries.
$ select * from shipments.shipment;