How I would design a reservation system

แชร์
ฝัง
  • เผยแพร่เมื่อ 14 ต.ค. 2024
  • 📘 T3 Stack Tutorial: 1017897100294....
    🤖 SaaS I'm Building: www.icongenera...
    ▶️ Generate Chapters: ytchaptersgene...
    💬 Discord: / discord
    🔔 Newsletter: newsletter.web...
    📁 GitHub: github.com/web...
    📺 Twitch: / webdevcody
    🤖 Website: webdevcody.com
    🐦 Twitter: / webdevcody

ความคิดเห็น • 61

  • @havoq8257
    @havoq8257 11 หลายเดือนก่อน +19

    An auto expiring Redis KV pair would probably be the best approach. The key being the Cabin Identifier and Value either a JSON string or a string like `user_id::expiration/creation`. You could also have a buffer period on the expiration timestamp or increase the reservation duration upon receiving a payment intent, and revert it if a payment intent failure event occurs.

    • @dhruveshk9457
      @dhruveshk9457 10 หลายเดือนก่อน +1

      you are changing your source of truth to something which doesn't guarantee strong consistency and is in memory volatile

  • @hugomartin8765
    @hugomartin8765 11 หลายเดือนก่อน +8

    I'm new in the development after changing my career path. I'm learning a lot with this kind of videos. It helps me to understand better how things work. Thank you for your time!

  • @wchorski
    @wchorski 11 หลายเดือนก่อน +4

    definitely like this practical logic crash courses. I'm currently trying to figure out an equipment rental app logic, so this is very on relevant. It's definitely builds confidence seeing you also tackle these same problems with different edge cases.

  • @veedjohnson
    @veedjohnson 11 หลายเดือนก่อน +4

    Can I ask that you never stop these? ❤️
    We just started making system design compulsory in my team for every feature and sometimes it confuses me but your videos are really helpful

  • @DevMastery
    @DevMastery 11 หลายเดือนก่อน +7

    In this type of system, especially at high volumes, we have to be super careful about race conditions and database lock-ups.
    One approach is to separate reservations and reservation expiries into 2 different tables so that we can put a unique constraint on the cabin number field in the reservations table and avoid a race condition. Then, counter intuitively, we should populate the reservation expiry table before we populate the reservation table as part of a single transaction, that way if we fail to set an expiry we don’t wind up with an indefinite reservation.
    Next, we need a table that tracks pending orders and prevents an expired reservation from being deleted while the order is in progress.
    Finally, we need a background job running every so often (e.g 10-15 seconds) that deletes expired reservations not currently part of a pending order. This job should be forgiving if it does not find a reservation that matches a given expiry (no error in that case, just return successful).

    • @CanRau
      @CanRau 11 หลายเดือนก่อน +1

      If you populate expiry & reservation within a transaction why would the order matter if you roll back the transaction if any write fails?

    • @DevMastery
      @DevMastery 11 หลายเดือนก่อน +2

      @@CanRau I should have been more careful about my choice of the word “transaction”. I meant transaction as in a single round trip from the user perspective. When using a formal transaction mechanism like the ones provided by many relational databases, you are 100% correct that the order does not matter. However, distributed systems, and certain NoSQL databases do not support formal transaction mechanisms and in those cases we need to manage things ourselves and the order can help us simplify things (i.e. avoid having to write a manual rollback or compensating transaction).

    • @CanRau
      @CanRau 10 หลายเดือนก่อน +1

      Aaah I see that makes sense! thanks for clarifying 🙌

  • @deezydoezeet
    @deezydoezeet 10 หลายเดือนก่อน +1

    Thanks a lot Mr Cody. I recently built a reservation system for someone but it was just a Proof Of Concept so I didn't actually consider the cases for multiple users racing to reserve a particular resource. This was an eye opener for me ❤

  • @vitorfigueiredomarques2004
    @vitorfigueiredomarques2004 11 หลายเดือนก่อน +10

    Remember, you need to remember to be careful with eventually consistent databases and non-atomic operations in those kinds of systems. For instance:
    If you check if the reservation expired in the database and then make another separate query to update the user (you are not performing an atomic operation), some other user can take that reservation in the time between those queries so that the user will lose his reservation. Or the read could hit a replica of the database that doesn't have the most updated version of the reservation (for instance, if your database uses asynchronous master-slave replication and you didn't tell it to read from the master). Probably some users will be confused or angry.

    • @WebDevCody
      @WebDevCody  10 หลายเดือนก่อน +1

      thanks for pointing this out. I made this video with the assumption of ACID compliant databases, but I probably should have put more thought in to talking about it. Doing some type of conditional update to obtain the lock and have it throw an exception if the lock already exists and isn't expired is probably the best approach assuming you have consistent writes in your database.

  • @taquanminhlong
    @taquanminhlong 10 หลายเดือนก่อน +1

    Available -> reserving (purchasing) -> reserved (purchased)
    Use redis expire key for the purchasing session, having session means it's temporary locked

  • @ardianhotii
    @ardianhotii 10 หลายเดือนก่อน

    I like this video a lot, thank you, I've started building a side project that works almost identical to this. It's an app that is for booking a slot in a gaming center for a certain time , but I'm not that good with forms that have datetime picking, so it's a new challenge for me, and watching your videos is helping a lot. Also I wanted to use convex for this app since it has the websocket feature where I can display in real time which slot is taken in certain hours .Thank you again. Keep going

  • @hijazi479
    @hijazi479 8 หลายเดือนก่อน

    I worked on the booking systems for co-working spaces, addressing various scenarios where users may book resources for different durations (minutes, hours, or days). Uncertainty exists regarding which user will reserve a resource and for how long. It's possible that one user may book a resource for one hour, while others may book the same resource for varying durations on the same date. In such cases, when a user initiates a booking for a resource or seat, it becomes necessary to temporarily lock that resource or seat for a specific duration, such as 5 minutes, on a particular date and time.
    During this lock period, the resource or seat should remain available for booking by other users, either for the same date but a different time or for different dates but the same time. This posed a challenge, making the system somewhat intricate.
    Then there was another challenge with payment system, Our payment gateway was behaving differently then expected if you double press Submit button after 3D verification it will make two api calls to call-back uri, one for success case and one for failure. because payment gateway never process one payment checkout multiple times.

    • @mohamedsadek9759
      @mohamedsadek9759 5 หลายเดือนก่อน

      @hijazi479
      So can you give me insights On how to solve this case

  • @dddavet9652
    @dddavet9652 11 หลายเดือนก่อน

    Locks are generally used almost in all applications. One of the ways to store a lock is actually on a Cache. I use Redis, it's fast and reliable.

  • @IvanRandomDude
    @IvanRandomDude 11 หลายเดือนก่อน +5

    I made similar thing few years ago. I can tell right away based on my own burn that this suffers from one serious bug: if payment is issued and the webhook comes after expiresAt. Acceptable fix was to extend expiresAt after payment is issued. It worked ok for our system although it is not perfect solution since we cannot predict how long will it take for webhook to hit our system. It is usually very fast but you never know. If it fails for some reason then you will have to wait for retry which can take longer.

    • @IvanRandomDude
      @IvanRandomDude 11 หลายเดือนก่อน +2

      But this is more than ok solution for small apps where you have anything less than dozen bookings per hour. The chances of this happening are so low that it is much cheaper to manually fix these issues when they occur then to implement something more advanced. Obviously, on a large scale when you have millions of bookings per day we would have to do way way wayyy better than this.

    • @WebDevCody
      @WebDevCody  11 หลายเดือนก่อน +2

      In that case it sounds like you’d need another flag or status on the seat to mark it as “pending” which would also act as a reservation to prevent people from buying. I guess I’m wondering what you do if the webhook takes hours to come in, or never comes in? After a certain amount of time you’d need to void the persons payment and open the seat probably? That might be a rare edge case

    • @IvanRandomDude
      @IvanRandomDude 11 หลายเดือนก่อน

      @@WebDevCody It is indeed very rare edge case. So rare than we basically ignored it, we assumed all the webhooks will be received after 10 minutes. We agreed that when it happens we will fix it manually by support. It never happened. But now that we are speaking about it I am curious to investigate and try to solve this problem just for fun.

    • @IvanRandomDude
      @IvanRandomDude 11 หลายเดือนก่อน +2

      But again, this decision to ignore the edge case is justified when you are operating on a small scale. "Once in a million" edge case will happen once a year on small scale which is fine most of the time. But it will happen dozens of times per day on large scale and no support can fix that.

    • @IvanRandomDude
      @IvanRandomDude 11 หลายเดือนก่อน

      This is perfect example how back end starts being relatively easy on a small scale but it then becomes super super suuuper hard on larger scale.

  • @focusotter
    @focusotter 10 หลายเดือนก่อน +1

    When that ticket master thing happened, my team celebrated because we scaled to support it....then we had to tone down our celebrations because another team didn't have the greatest day 😅

    • @WebDevCody
      @WebDevCody  10 หลายเดือนก่อน

      I'm still waiting in the ticket queue for months for my taylor swift tickets 😝

  • @mr.daniish
    @mr.daniish 10 หลายเดือนก่อน

    Loving these backend system design videos!

  • @RitchieCulanag
    @RitchieCulanag 8 หลายเดือนก่อน

    I think we'll need more of these, like how to design a system.

  • @andrewwashburn9357
    @andrewwashburn9357 10 หลายเดือนก่อน

    I’ve implemented this same design for my system. But I am interested in the more sophisticated patterns!

  • @bvdlio
    @bvdlio 11 หลายเดือนก่อน

    Hey, love your video :D
    I have a question about the design.
    I don't see the use of a Lock in your design. Wouldn't there be a race condition in this case, where you first check if its reserved, and then reserve it?
    If a seat is not reserved, and two users ask to reserve at the same time, they will both confirm there is no reservation, and then create a Reservation.
    query 1: user_1 checks if reserved: returns false
    query 2: user_2 checks if reserved: returns false
    query 3: user_1 claims reservation
    query 4: user_2 claims reservation
    I guess if there is a single row in the reservations table per seat and you just override it the user_id that reserves it, the last of the simultaneous reservations will be the user that gets the reservation, which is kind of fine.
    My apologies if I am understanding this wrong. You do mention locks at the end, but I don't see them considered in the design.

    • @WebDevCody
      @WebDevCody  11 หลายเดือนก่อน +2

      If two users ask at the same time, you’d want an ACID compliant database and use a transaction or a conditional write to claim the reservation. That would prevent multiple users from claiming the lock

  • @wvvwwwvvw
    @wvvwwwvvw 11 หลายเดือนก่อน +3

    So what if the user starts the payment and sends the request to a PaymentService at the very last moment of the cabin expiration, then you could end up in a situation, where somebody else will get a terrible UX, of getting a cabin first, and then seeing it has already been taken, after the webhook of the PaymentService actually creates a record for the Cabin booking.

    • @WebDevCody
      @WebDevCody  11 หลายเดือนก่อน +3

      yeah that sounds like a potential edge case you'd need to think about. I think you could just try to obtain the lock right before a user submits the payment info. It's either that, or you need to keep refreshing the lock periodically if the user is actively doing something on your buy seat wizard.

  • @SeibertSwirl
    @SeibertSwirl 11 หลายเดือนก่อน +1

    Good job Loverrrrr!!!! Since someone already said good job babe 😂

    • @WebDevCody
      @WebDevCody  11 หลายเดือนก่อน +1

      😂 why you do late to the party?!

  • @saiyijinprince
    @saiyijinprince 11 หลายเดือนก่อน

    This is something that can be done either on the frontend or the backend but wont it be even better if user2 cant even select the cabin user1 reserved. To me it makes sense to do it in the backend, so when user2 loads the seat map, it should just show the reserved seat as unavailable

    • @WebDevCody
      @WebDevCody  11 หลายเดือนก่อน

      Sure, but what if user2 loads the seat map and just waits for a minute. By that time other seats could have been bought. So either you have to add polling or websockets to make the Ui refresh, or just refresh the seats if the user clicks one that was already reserved

  • @nfteague
    @nfteague 10 หลายเดือนก่อน

    I feel like Redis would be a better integration?
    Redis for the temp locks, and then fully booked reservations within the database. This would reduce the risk of any double booking through disc latency. Thoughts?

    • @nfteague
      @nfteague 10 หลายเดือนก่อน

      Also, great videos! I love the way you break these topics down. 😄

    • @WebDevCody
      @WebDevCody  10 หลายเดือนก่อน +2

      I don’t think disc latency is important. Having an acid compliant data store with transactions would be necessary to prevent double booking.

  • @nepalxplorer
    @nepalxplorer 10 หลายเดือนก่อน

    This is so simple; I was hoping for something else.

    • @WebDevCody
      @WebDevCody  10 หลายเดือนก่อน

      What were you looking for?

  • @dandogamer
    @dandogamer 10 หลายเดือนก่อน

    This problem gets way more complicated when you consider a distributed system. I imagine that's where ticket master fluffed up

  • @crum--business
    @crum--business 11 หลายเดือนก่อน

    Loved it , just amazing❤❤❤❤❤

  • @felixkiptoo421
    @felixkiptoo421 10 หลายเดือนก่อน

    Great information.

  • @Supersnoopadoop478
    @Supersnoopadoop478 11 หลายเดือนก่อน

    Neat real world example

  • @onakoyakorede
    @onakoyakorede 11 หลายเดือนก่อน

    Great video. How about we skip steps 4 and 5, which could lead to a bad user experience, and just filter out the cabins that are locked from displaying in the customer UI.
    Then, we use events to update the cabin whether as booked or now available for booking after its expiresAt field is due.
    What do you think?

    • @WebDevCody
      @WebDevCody  11 หลายเดือนก่อน +1

      Yeah for sure, the ui should show open / closed cabins. Ones you can’t buy should be red or grayed out. You could just join the cabins with non expired reservations and send that list back from the api to show the open rooms

    • @onakoyakorede
      @onakoyakorede 11 หลายเดือนก่อน

      @@WebDevCody Makes sense. Returning everything but having its status displayed for the users.

    • @WebDevCody
      @WebDevCody  11 หลายเดือนก่อน

      @@onakoyakorede but yes a more sophisticated system would be use events or websockets to update the view for users, but that might add lot of complexity and costs for a larger scale system. Sometimes just refreshing when the user clicks an already reserved room can save a ton of money and complexity

    • @satansauce666
      @satansauce666 10 หลายเดือนก่อน

      Hey I'd like to hear your thoughts on this topic about a scenario what I think is quite common on some "super-sales" kind of events. Say a *ticket* to a highly wanted *gig* is at a -70% sale or something. And the sales event starts at 8am. Multiple persons refresh into the page at the exact same time (with a date "error" percentage due to internet speeds). How to "keep the truth" in these kinds of scenarios for users? The UI for the end user cannot be what was initially loaded right. The application cannot send requests every second to check availability=true or not right, because that would make the app heavy. I'd really like to hear a very simplified explanation how these kinds of situations are handled or a keyword or two what i should search and study. I'm asking as a noob fe-oriented fullstack dev who's more interested in system architecture. I've recently built a web store with our team where the first user to click the *product* into his *cart* is the one the *product* is reserved to. But I think there lays a problem where if another person who has loaded the same products list at the same time as the other... you see where this is going. This app we've created has a very low traffic/orders placed per day amount, but i am very interested in how to scale applications. Thanks alot for possible responses.

    • @WebDevCody
      @WebDevCody  10 หลายเดือนก่อน +1

      @@satansauce666 if you have an event sale starting at a certain time, you may want to just have logic in the UI to show new content at 8am.

  • @binodchaudhary17
    @binodchaudhary17 10 หลายเดือนก่อน

    What would you suggest for real time updates on booking page? Like, users need to know, if cabin is booked or not without making api request.

    • @WebDevCody
      @WebDevCody  10 หลายเดือนก่อน

      Websockets or push server events

  • @AveN7ers
    @AveN7ers 11 หลายเดือนก่อน

    Good job, babe. Very informative

    • @SeibertSwirl
      @SeibertSwirl 11 หลายเดือนก่อน +1

      Lmaoooooooo hey! that’s my line!

    • @WebDevCody
      @WebDevCody  11 หลายเดือนก่อน +3

      You better back off, my wife won’t like it

  • @omarnazih9685
    @omarnazih9685 10 หลายเดือนก่อน

    I have a question. How to deal with dates and this type of systems?

    • @WebDevCody
      @WebDevCody  10 หลายเดือนก่อน

      Date times should probably just be stored as ISO dates in UTC timezone, Zulu time

  • @georgeliu1519
    @georgeliu1519 หลายเดือนก่อน

    This wouldn’t work well for high concurrency distributed system, also the seat should appear available without the user clicking on it to find out whether it’s available or not. Really bad ux

  • @namhynguyenhoang1043
    @namhynguyenhoang1043 2 หลายเดือนก่อน

    Nothing special