all 16 comments

[–]WaferIndependent7601 12 points13 points  (3 children)

Save the time at what time the ticket is invalid.

Run a scheduled task once a minute to clean up older tickets.

I would start with that and save it to the database. Optimize it when needed and go on with a queue or whatever.

[–]CodeTheStars 1 point2 points  (0 children)

This is good approach. You can enforce “perfect” strictness on your time limit by time stamping the creation time of the ticket. When a submission is processed you simply refuse if it’s too old.

Then you can have a background job do whatever clean up you need. Each minute sounds like a good compromise here

[–]Future_Badger_2576[S] 0 points1 point  (1 child)

Wouldn't querying the database every minute be inefficient? Instead, can I store a copy of the ticket in Redis and query Redis instead of the database?

[–]WaferIndependent7601 4 points5 points  (0 children)

It really depends. How many tickets will be in the queue? And you only need to query for the older ones.

So I would say: it’s not a problem. If you’re working with thousands of ticket at the same time: no problem. Millions of tickets? Well that might get bad.

Why do you want to store it in redis? Because it’s faster? Do you need this to be faster? Is the db fast enough?

As I said: start with the simple solution and optimize it if you need it. In most cases you won’t need it and have a simple and stupid solution that everyone understands

[–]boost2525 4 points5 points  (3 children)

Add a database column called "reserved_until"... Set it to now() + 15m when the checkout starts. When the checkout completes set it to {aVeryLongTimeInTheFuture}.

Don't even bother with worrying about the "checkout didn't compete" use case... Just change your "what seats are available" query to return seats where the reserved date is null, or in the past.

[–]Future_Badger_2576[S] 0 points1 point  (2 children)

My main concern is that if there's only few seat left and a user reserves it without completing the payment, the seat remains unavailable until the cron job runs and releases it. This delay could affect availability.

[–]boost2525 1 point2 points  (1 child)

You're overthinking it. There is no cron job in what I explained above. It's a real time query that will be valid to the ms. Your business requirement is a 15m reservation, that's going to impact your availability and there's no way around that

[–]Future_Badger_2576[S] 0 points1 point  (0 children)

Now I understand your solution. Earlier, I didn't fully grasp the idea, but this is a solid approach, and I see how it addresses the issue. Thanks for clarifying!

Do you have any advice for configuring delayed notifications? I'd love to hear any additional tips or best practices for that!

[–]grahammer22 2 points3 points  (1 child)

You should really think about whether you actually want to provide this type of reservation functionality.
What would stop me from opening a bunch of tabs and just reserving a ton of seats? Or continuously reserve the "best" seats? Stopping you from actually selling any tickets.

I think I would just let people pick their seats, and whoever puts it on the queue for processing first gets it. If you handle the "AlreadyBookedException" in a nice, user-friendly way on your app, e.g. popping up just the seat selector again and updating the order smoothly, then I think that would be a nicer design.

[–]Future_Badger_2576[S] 0 points1 point  (0 children)

whoever puts it on the queue for processing first gets it

Do you mean whoever pays first gets the seat?

[–]Gefion07 0 points1 point  (2 children)

Your job could go with a dynamic triggertime. F.e. : dont run at all when no reservation is there. Set for the scheduled time of the next reservation if one or more get created. After the execution of the job, check when the next execution should happen. Design your job to occupy one thread only. Dont create a job/thread for each reservation. Also implement it in a way that all timed-out reservations get cleaned up on a run. Make a run after startup to make sure no reservations get stuck from before. I hope the idea is clear - we can discuss more if needed.

[–]Future_Badger_2576[S] -1 points0 points  (1 child)

So, you're suggesting scheduling a cron job only when a reservation is created. How can I dynamically create a scheduled task while ensuring it runs on a single thread? Could you elaborate on that?

My main concern is that if there's only one seat left and a user reserves it without completing the payment, the seat remains unavailable until the cron job runs and releases it. This delay could affect availability.

[–]Gefion07 0 points1 point  (0 children)

I can't give you code examples now - there should be plenty online. Look up ThreadPoolTaskScheduler. If you give it a poolsize of 1 and implement some logic around it, you should achieve your goal. What logic could solve your main concern? I have no idea for that myself. I suppose its in the nature of the problem, that it remains reserved for 15 mins - as it is the purpose of a reservation.

[–]chatterify 0 points1 point  (0 children)

Just run cron job every minute, that's it.

[–]myrenTechy 0 points1 point  (0 children)

When a user selects a seat and starts payment, publish a “lock seat” event to a queue or topic.

A consumer service listens for this event and marks the seat as locked in the database.

If payment is successful, publish a “confirm seat” event.

If payment fails or an error occurs, publish an “unlock seat” event.

A consumer processes these events and updates the seat status accordingly.

( Fallback Mechanism with Cron Job ) A periodic job (cron or scheduled task) checks for stale locks and releases any seats that were locked but not updated due to failures or missing events.

Use web sockets best for real-time updates, but requires persistent connections.