People booking for an event, How do I properly restrict the maximum number of bookings? (concurrency)

StackOverflow https://stackoverflow.com/questions/22150920

  •  19-10-2022
  •  | 
  •  

Question

I guess this is a classic concurrency question.

I have people signing up to participate in an event. The event can handle a maximum number of participants.

This is a Symfony application with a PostgreSQL database.

What's the best way to ensure that the event is not overbooked?

Let's say I have entities called Event, Person and Booking. Booking has one to many relationships with Person and Event.

I display a page about the event. I count the current bookings and show a "Book now" button if count is less than the max.

Here's some psuedocode of how I've done this previously:

On the action for the Book now button:

Count bookings
if count >= max
  return "Sorry, this event is full"
else
  Create booking
  Flush entity manager

  Count bookings again

  if count > max
     Delete booking
     return "Sorry, this event is full"
  endif

endif

I think this method is safe but not ideal. I think it could result in two people booking when there is one space left and both being rejected. The real world chance of that happening is probably close to zero and I guess the users will try again but ... it would be nice to do this correctly.

Is there a better way to do this?

I've read this: Handling the concurrent request while persisting in oracle database? and a similar question I asked a few months ago. It seems that optimistic locking is a good strategy when maximum bookings = 1 such as an airline seat. In that case I probably wouldn't have Booking entity at all. Event would just have a Person or not.

No correct solution

OTHER TIPS

Take a look at the doctrine docs Concurrency and Transactions, there are a few options that you could use.

I would agree that optimistic locking is probably the way to go, but you wouldn't have to change your current logic. Just add a new version field (type serial is best) to the entity you want to insert into, and when you do your initial SELECT, you pass in the unique version number. Then when you insert, if the version has changed, you know that someone else has already booked and the insert will not happen.

The docs have some good examples there for Optimistic Locking

UPDATE

Optimistic locking will work when updating the entity. For inserting a new entity, transactions will be the best bet.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top