Deliver your first outbox message
Copy page
In this tutorial you start QueueBox with Docker Compose, insert one row into the outbox table, and watch QueueBox deliver that row to an HTTP receiver. At the end, the row is in state sent.
Before you start
Section titled “Before you start”You need Git, Docker with the Compose plugin, and curl. The stack uses the ports 8080 and 5432 on your machine, so stop anything else that listens on them.
Start the stack
Section titled “Start the stack”Clone the repository and start the Compose stack.
git clone https://github.com/alternayte/queuebox.gitcd queueboxdocker compose -f docker-compose.yml --env-file .env.example up -d --buildThe stack runs three services:
| Service | What it does |
|---|---|
postgres |
PostgreSQL 16. QueueBox creates its tables in it at startup. |
queuebox |
QueueBox, built from the repository. It reads examples/queuebox.yml. |
receiver |
A small HTTP server. It answers 200 and prints every request body it receives. |
The first build compiles QueueBox, so it takes some time. Ask QueueBox whether it is ready:
curl http://localhost:8080/healthA ready instance answers with status 200 and a body that starts with {"status":"healthy". If curl cannot connect, wait a moment and send the request again.
Read the route
Section titled “Read the route”Open examples/queuebox.yml. The configuration names one HTTP destination and a route to it:
# fragmentdestinations: webhook-api: type: http baseUrl: http://receiver:8080 path: /webhook timeoutMs: 30000
routes: - topicPattern: "order.*" destination: webhook-apiA row whose topic matches order.* goes to webhook-api. QueueBox sends it as an HTTP POST to http://receiver:8080/webhook.
Insert an outbox row
Section titled “Insert an outbox row”Your application sends a message with one INSERT into the outbox table. Run that insert through psql in the postgres container:
docker compose -f docker-compose.yml exec -T postgres psql -U queuebox -d queuebox <<'SQL'BEGIN;INSERT INTO outbox (topic, key, payload)VALUES ('order.created', 'order-1001', '{"orderId":"1001","amount":42}');COMMIT;SQLpsql prints BEGIN, INSERT 0 1 and COMMIT. The row names three columns:
topicisorder.created, so the routeorder.*matches it.keyisorder-1001. The rows of one key arrive in insert order.payloadis the JSON body that the receiver gets.
In a real application, the same transaction also writes the business row, for example the order itself. Both rows commit together, or neither commits.
Watch the delivery
Section titled “Watch the delivery”Read the log of the receiver:
docker compose -f docker-compose.yml logs receiverThe last line shows the delivery:
receiver-1 | receiver listening on 8080receiver-1 | delivered POST /webhook {"amount":42,"orderId":"1001"}The keys of the body are in a different order. PostgreSQL stores payload as JSONB, which keeps the content of a JSON object but not the order of its keys.
QueueBox polls the outbox every 100 milliseconds in this configuration, so the line appears at once. If the line is absent, run the command again.
See the row in state sent
Section titled “See the row in state sent”Read the row back from the outbox table:
docker compose -f docker-compose.yml exec postgres psql -U queuebox -d queuebox \ -c "SELECT topic, key, state, attempt FROM outbox;"The output shows the row in state sent:
topic | key | state | attempt---------------+------------+-------+--------- order.created | order-1001 | sent | 0(1 row)attempt counts the failed deliveries. It is 0, because the receiver accepted the first delivery.
Clean up
Section titled “Clean up”Stop the stack and delete its database volume:
docker compose -f docker-compose.yml down -vWhat you did
Section titled “What you did”You started QueueBox, wrote one outbox row, and saw QueueBox deliver it to an HTTP endpoint and mark it sent. QueueBox did the polling, the routing and the delivery. The application wrote one row.
Next steps
Section titled “Next steps”- Receive a webhook shows the other direction: the inbox.
- Write outbox rows shows the insert inside a business transaction, with headers, a schedule and a retry ceiling.
- Fan out over HTTP sends rows to more than one HTTP endpoint.
- Delivery semantics states what QueueBox promises for a row it delivers.