0

I have a plan as to how I would go about doing this and wanted to know if I am headed in the right direction or if there is a better way altogether.

From Firestore Documentation: In the case of a concurrent edit, Cloud Firestore runs the entire transaction again. For example, if a transaction reads documents and another client modifies any of those documents, Cloud Firestore retries the transaction. This feature ensures that the transaction runs on up-to-date and consistent data.

I have a react front end and node express backend.

  1. Front end sends request to create a checkout session.

  2. In the backend I simply parse the request with the required data then send it to Stripe and receive Stripe's response.

  3. Then for each product P in the customers cart:

    We create a Firebase transaction in which:

        - get (P) from Firestore
        - if P.stock >= 1 then decrement by one and send the redirect uri from stripe to frontend
        - else Item is out of stock send custom Failed payment response to front end
    

Now if two people are trying to purchase the same item and we only have 1 of that item in stock, only one person will be able to complete the payment flow. Is that correct?

I am adding this image to better explain what the flow would look like: Flow Diagram

  • You must also make sure you re-increment your stock, and delete the customer cart if the cart content is never purchased. Else your stock doc may end up not being up to date. (Imagine a case where the same customer retries to purchase an item after the first payment failed, but (s)he can't because, although the previous charge failed, the stock were never re-incremented and has a value of 0...) – Alan Kersaudy Jun 04 '22 at 09:56
  • You are right thank you @AlanKersaudy I will account for that case as well ! – Abhishek Sharma Jun 06 '22 at 14:27
  • I'm glade it helped, don't forget to upvote/accept the question if you think my answer is worth it. – Alan Kersaudy Jun 07 '22 at 21:48

1 Answers1

1

To avoid such race condition you must trigger events earlier at a point that will take more time for your customer to start the purchase process than the longest API call scenario.
If you have a basket system, you could simply decrement the stock as soon as the item is added to it. Then when your basket is deleted after the purchase do nothing to the stock else after you make the basket expire after a certain time increment back your stock.
You can still create such a basket-like system even without the user seeing it in the front end. When the purchase succeeds, retrieve your basket doc id from the session metadata and delete it. If you don't delete it after a payment succeeds, that is, before expiration, increment your stock back.
I hope my answer is not too confusing, share the implementation you're heading for, I curious!

Alan Kersaudy
  • 739
  • 7
  • 15