I’m currently building an event ticketing system in Elixir and I’m looking for advice on properly handling race conditions around ticket inventory.
I’m using Oban for background processing with jobs responsible for:
-
Initiating payments
-
Delivering tickets after successful payment
-
Restoring tickets when payment fails or expires
The main inventory field being updated is rem_quantity.
I also have a cron job that periodically checks for pending orders older than 5 minutes and marks them as expired.
My concern is around concurrent updates to ticket inventory. For example:
-
Multiple users attempting to reserve the same ticket simultaneously
-
A payment succeeding while the expiration cron job is running
-
Ticket restoration jobs conflicting with payment confirmation jobs
At the moment, I’m worried this could lead to inconsistent rem_quantity values or overselling.
I’d appreciate guidance on best practices for handling this in Elixir/Postgres. Specifically:
-
Should I use database row locking (
FOR UPDATE)? -
Is optimistic locking enough for this use case?
-
What’s the recommended approach for inventory reservation in ticketing systems?
-
How should Oban jobs be structured to remain idempotent and avoid duplicate restoration/delivery operations?
Would also appreciate examples or patterns from production systems if anyone has implemented something similar.























