A Pattern for Handling Concurrent Seat Reservations
Distributed locking with Redis solved our double-booking problem at Offizonee. Here's how we used BullMQ queues and atomic transactions to guarantee no two users book the same seat.
At Offizonee, our event management platform needed to handle thousands of concurrent seat reservation requests without ever double-booking a seat. This is a classic distributed systems problem.
The Challenge
When 500 users try to book the last 50 seats simultaneously, naive database checks fail. By the time user A's INSERT runs, user B has already read the same "available" count. Both get confirmed — and you've oversold by 2x.
Our Solution: Three-Layer Defense
Layer 1: Redis Atomic Operations
We use Redis INCR/DECR operations on a seat counter key. These are atomic — no two requests can read the same value. Each reservation attempt decrements the counter; if it goes below zero, we reject the request.
Layer 2: BullMQ Job Queue
Instead of processing reservations inline, we push them to a BullMQ queue with a concurrency limit of 1 per event. This serializes writes to the database while keeping the API responsive. The queue consumer validates the reservation against the database and confirms or rejects it.
Layer 3: Database Constraints
A compound unique index on (event_id, seat_number) ensures that even if layers 1 and 2 fail, the database won't allow a duplicate.
Results
The pattern is reusable for any resource with contention: coupon codes, limited-edition items, or appointment slots.