Skip to main content

The outbox pattern for publishing events

·4 mins

Hey, hope you’ve had a good week!

Today’s post is the second part of a mini-series on publishing events, and today I explain the outbox pattern.

There’s also links to articles on silos, integrations, and building reliable log delivery.


The outbox pattern for publishing events

As mentioned last week, with data contracts we want to move to a model where data and events are published to consumers, rather than replicated from databases. That requires adopting new patterns and providing the tooling that enables them.

Last week we looked at the simplest pattern, where you just write events to an event broker after you write to the database. However, that pattern has one major drawback, and that’s known as the dual-write problem.

This happens when you have a system that needs to update two different places, in our case the database and the event broker. Logically, that should be one operation, but in this case it will be two operations, as shown below. If one fails, such as the write to the event broker, then data in those two systems will be inconsistent.

A sequence diagram showing a user initiating an action, service handling an insert or update in the database, and an event broker publishing an event for downstream consumption, with a red cross indicating failure or cancellation.

The outbox pattern is designed to solve this problem.

It does this by storing the event in the same database transaction as the business change, as a single operation, with the event written to an outbox table.

A diagram illustrating data flow from a service to a database, involving application tables and an outbox table within a transaction, which sends events through an event broker to a data warehouse.

The SQL for this write would look something like this:

BEGIN;

UPDATE orders
SET status = 'PAID'
WHERE order_id = 123;

INSERT INTO outbox_events (id, type, payload, created_at)
VALUES (uuid(), 'OrderPaid', '{"orderId":123}', now());

COMMIT;

Now, if either of those writes fail, the transaction is rolled back and no data will be written.

If they both succeed, the event will be processed asynchronously by a service that reads the outbox tables and publishes them to the broker. When successfully written to the broker the record in the outbox table is deleted.

In this example the payload is just arbitrary JSON, which could still be invalid, but it could be more structured, and/or validation can be done in code as the event is generated.

This ensures strong data consistency between the database and the event broker, as well as being resilient to any issues writing to the broker.

However, it does add some complexity. It can also impact performance of the database, particularly if there are high volumes of events being generated. Most relational databases are not optimised for high-churning tables such as the outbox tables.

There is an alternative pattern that alleviates some of these drawbacks called the listen to yourself pattern. I’ll explain what that is next week.


Web scraping used to be such a pain. I remember writing Perl scripts to scrape the web back in the early 2010s, and they would take ages to build, only to break as soon as the site changes.

(You can still see examples of these scripts I created for my personal use on the CPAN (Perl’s version of PyPI), including scraping the Arsenal FC ticket website so I knew when tickets were released!)

Luckily, the industry has moved on, with resilient, compliant, and performant web scrapers available.

Of course, that now includes the use of AI, which completely automates the entire web scraping pipeline!

This year I’m attending the OxyCon, a FREE virtual conference, to join the community and learn the latest in web scraping and:

  • How to build a scalable e-commerce scraping strategy;
  • How feedback loops can be established to improve AI models with scraped data;
  • How to structure messy scraped data efficiently with an API (live demo);
  • How to build a price comparison tool with AI studio.

Come join me on October 1st! Sign up here.


Are Silos Always a Bad Thing? by Joe Reis

I like this take on silos. They are inevitable, so it’s about working with them.

Why ‘API Gateway’ is Not an Integration Style by Daniel Kocot

Not strictly an article on data, but you will recognise many of the arguments being made here as data is also largely an integration problem.

How we built reliable log delivery to thousands of unpredictable endpoints by Gabriel Reid at Datadog

Interesting apprach to building a log delivery system.


Being punny 😅

The contractor who recently finished remodelling my kitchen has been charged with counterfitting.


Thanks! If you’d like to support my work…

Thanks for reading this weeks newsletter — always appreciated!

If you’d like to support my work consider buying my book, Driving Data Quality with Data Contracts, or if you have it already please leave a review on Amazon.

Enjoy your weekend.

Andrew


Want great, practical advice on implementing data mesh, data products and data contracts?

In my weekly newsletter I share with you an original post and links to what's new and cool in the world of data mesh, data products, and data contracts.

I also include a little pun, because why not? 😅

(Don’t worry—I hate spam, too, and I’ll NEVER share your email address with anyone!)


Andrew Jones
Author
Andrew Jones
I build data platforms that reduce risk and drive revenue.