Skip to main content
  1. System Design Components/

Archetype 8 — Time-Bounded Exclusive Allocation #


What this archetype is #

A user gets a temporary exclusive hold over a scarce resource. The hold expires unless confirmed.

Examples: ticket hold, appointment hold, waitlist claim window.

We will use ticket hold as the running example.


Layer 1: Entities and Postgres table design #

HoldState
BookingState
InventoryState
create table ticket_holds (
  hold_id uuid primary key,
  seat_id bigint not null,
  user_id bigint not null,
  status text not null default 'ACTIVE',
  expires_at timestamptz not null,
  created_at timestamptz not null default now(),
  unique (seat_id, status) deferrable initially immediate
);

create index ticket_holds_expires_idx
on ticket_holds (status, expires_at);

In practice, the uniqueness is often implemented as:

  • one active hold row per seat
  • or seat inventory row plus hold_id

Layer 2: Write path mechanics #

Create hold #

insert into ticket_holds (
  hold_id, seat_id, user_id, status, expires_at
) values (
  $1, $2, $3, 'ACTIVE', now() + interval '10 minutes'
);

Confirm hold #

begin;

update ticket_holds
set status = 'CONFIRMED'
where hold_id = $1
  and status = 'ACTIVE'
  and expires_at > now();

insert into bookings (...);

commit;

Expire hold #

update ticket_holds
set status = 'EXPIRED'
where status = 'ACTIVE'
  and expires_at <= now();

Layer 3: Fault tolerance #

  • duplicate hold
  • expired hold not released
  • confirm-after-expiry race
  • cancel/confirm race
  • stale availability after hold expiry

Layer 4: Scale #

Default hotspots:

  • hot hold key
  • hold storms
  • expiry scan pressure
  • hold-store contention

Common mitigations:

  • partition expiry scans by time bucket
  • keep active holds in narrow indexed table
  • queue in front of hold creation for flash sales