Skip to main content
Articles/database-partitioning/outbox-table-partitioning-scaling-event-delivery-without-locking
Scenario Article

Outbox Table Partitioning: Scaling Event Delivery Without Locking

The Bottleneck Problem

Abstract Algorithms•Sep 8, 2026
💡 Executive Summary

Partition your outbox table to avoid write contention and speed up event reads—just remember to keep partitions balanced and keep your cleanup job in sync!

🎯 System Scenario & Requirements

System Goal

Partition your outbox table to avoid write contention and speed up event reads—just remember to keep partitions balanced and keep your cleanup job in sync!

Actors & Components

  • Domain Service
  • Partitioned Outbox
  • Event Publisher
  • Outbox Table (4 partitions)

Functional Requirements

  • TLDR: Partition your outbox table to avoid write contention and speed up event reads—just remember to keep partitions balanced and keep your cleanup job in sync!
  • 🚀 You’re building a microservice that writes domain events into a single outbox table as part of a transaction.
  • Under load, every write hits the same table, causing lock contention, slow commits, and a backlog of events for the publisher.

Constraints & Assumptions

  • Constraints are derived from the rebuilt scenario stages.

⚡ Execution Stages & Decision Trace

1

Stage 1 — Partitioning Strategy

Action / Decision:

Use table partitioning (PostgreSQL, MySQL, or a sharded NoSQL table) to spread writes across multiple physical segments.

Component Behavior:

Common strategies: Example: PostgreSQL hash partition

Observable Output: Common strategies: Example: PostgreSQL hash partition
Read Full Stage in Deep Dive ↓
📖

Deep Dive

Detailed Architectural Analysis

Scenario context

Partition your outbox table to avoid write contention and speed up event reads—just remember to keep partitions balanced and keep your cleanup job in sync! 🚀 You’re building a microservice that writes domain events into a single outbox table as part of a transaction. Under load, every write hits the same table, causing lock contention, slow commits, and a backlog of events for the publisher. The question is: **how…

This walkthrough focuses on The Bottleneck Problem.

Before making a design choice, clarify:

  • You’re building a microservice that writes domain events into a single outbox table as part of a transaction.
  • Under load, every write hits the same table, causing lock contention, slow commits, and a backlog of events for the publisher.
  • The question is: how do you keep the outbox write fast while still guaranteeing reliable event delivery?

Concepts in play: event-driven-architecture, transaction-isolation-distributed-acid, database-sharding

Stage 1 — Partitioning Strategy

  • Use table partitioning (PostgreSQL, MySQL, or a sharded NoSQL table) to spread writes across multiple physical segments.
  • Common strategies: Example: PostgreSQL hash partition
CREATE TABLE outbox (
  id          BIGSERIAL PRIMARY KEY,
  tenant_id   BIGINT NOT NULL,
  event_type  TEXT NOT NULL,
  payload     JSONB NOT NULL,
  created_at  TIMESTAMPTZ NOT NULL DEFAULT now()
) PARTITION BY HASH (tenant_id);

CREATE TABLE outbox_p0 PARTITION OF outbox FOR VALUES WITH (MODULUS 4, REMAINDER 0);
CREATE TABLE outbox_p1 PARTITION OF outbox FOR VALUES WITH (MODULUS 4, REMAINDER 1);
-- … up to p3

Observable outcome: Common strategies: Example: PostgreSQL hash partition

Stage 2 — Architecture Kit Diagram

  • { "version": 1, "title": "Partitioned Outbox with Pull‑Based Publisher", "description": "Writes go to a hash‑partitioned outbox; a polling service reads from each partition in parallel.", "view": "data-flow", "pattern":…

Observable outcome: { "version": 1, "title": "Partitioned Outbox with Pull‑Based Publisher", "description": "Writes go to a hash‑partitioned outbox; a polling service reads from each partition in parallel.", "view": "data-flow", "pattern":…

Stage 3 — Trade‑offs & Gotchas

Observable outcome: You can explain how “Trade‑offs & Gotchas” changes the architecture or implementation path.

Stage 4 — Quick Checklist

  • Choose a stable partition key that distributes writes evenly.
  • Monitor partition sizes ; add or drop partitions as needed.
  • Implement idempotent reads in the publisher to handle duplicate reads from partitions.
  • Schedule cleanup (e.g., DROP TABLE outbox p0 for old data) after confirming delivery.

Observable outcome: Schedule cleanup (e.g., DROP TABLE outbox p0 for old data) after confirming delivery.

End-to-end outcome

You’re building a microservice that writes domain events into a single outbox table as part of a transaction.

Alternatives considered

The source focuses on one primary design. A second architecture is not compared, so no alternative is invented here.

Failure and degraded modes

The source does not isolate a separate failure mode. Limits that matter for the scenario are called out in the stage decisions above.

✅

Key learnings

  • Use table partitioning (PostgreSQL, MySQL, or a sharded NoSQL table) to spread writes across multiple physical segments.
  • { "version": 1, "title": "Partitioned Outbox with Pull‑Based Publisher", "description": "Writes go to a hash‑partitioned outbox; a polling service reads from each partition in parallel.", "view": "data-flow", "pattern":…
  • Apply database-sharding to Trade‑offs & Gotchas.
  • Choose a stable partition key that distributes writes evenly.

Share this case study

Discuss architecture trade-offs and lessons with your team.

Share:XLinkedInReddit