问题
I'm using Slim in conjunction with Stripe's PHP Library to process payments in my application.
All is well, however up until recently, I have discovered an alarming fault in my system that I believe may be a much larger issue than I probably think. In my logic, at three separate checkpoints of the payment process I inspect the inventory in my (MySQL) database to ensure a user isn't purchasing more products than is available.
However, when multiple users make a request within approximately 500ms of each other, the payment system seems to process these requests all at once, resulting in a slew of issues ranging from incorrect and unbalanced inventory, to false user confirmation of successful payments.
Through some due diligence, I have narrowed a solution down to two options (although I may be selling myself short):
1) Use a Queueing System that, from my understanding, will queue these request and process them one at a time, creating a sort've first-come, first-serve basis.
2) Attach some middleware on to each request that will act as a queue and attempt to process each request synchronously (although this may be similar to what i already have in place)
Now with that said, any suggestions/opinions on these options? and obviously feel free to totally scrap my idealogy and point me in a different direction.
回答1:
Using TRANSACTIONS would be beneficial for this, since it appears that you've been faced with what is called a race condition.
Pulled from https://www.w3resource.com/mysql/mysql-transaction.php and I quote:
A transaction is a logical unit of work that contains one or more SQL statements. Transactions are atomic units of work that can be committed or rolled back. When a transaction makes multiple changes to the database, either all the changes succeed when the transaction is committed, or all the changes are undone when the transaction is rolled back.
A transaction begins with the first executable SQL statement. A transaction ends when it is committed or rolled back, either explicitly with a COMMIT or ROLLBACK statement or implicitly when a DDL (Data Definition Language (DDL) is used to manage table and index structure and CREATE, ALTER, RENAME, DROP and TRUNCATE statements are to name a few data definition elements) statement is issued.
LOCKING the table during a transaction will help prevent against a race condition.
Pulled from the same resource:
LOCK TABLES
tbl_name [[AS] alias] lock_type
[, tbl_name [[AS] alias] lock_type] ...
lock_type:
READ [LOCAL]
| [LOW_PRIORITY] WRITE
UNLOCK TABLES
More information and syntax can be found on the (official) MySQL website:
- https://dev.mysql.com/doc/refman/5.7/en/sql-syntax-transactions.html
- https://dev.mysql.com/doc/refman/5.7/en/commit.html
"About transactions", pulled from https://www.informit.com/articles/article.aspx?p=29312
A transaction is a sequential group of database manipulation operations, which is performed as if it were one single work unit. In other words, a transaction will never be complete unless each individual operation within the group is successful. If any operation within the transaction fails, the entire transaction will fail.
回答2:
So if i understand main problem is that you afraid that someone buy product that already are sold(payment is processing at this time)...
I think that you should leave this queuing system idea - becouse this is not clue here. Clue is your shop logic.
I don't know how your shop works, but from logic point of view product should be locked(allocated) in the moment when client cliking send order, not after payment process. Becouse not each payment may be successfull (what if client want to retry unsuccessfull payment with stripe or other paying method ?) .
回答3:
I've heard many horror stories around developers using queuing systems so I would definitely recommend against it. The first-come first-serve basis can often lead to errors that are hard to catch until after the code is in place - one developer I know in specific created a shop using a similar system only to find that many customers ended up with random items in their cart or getting to the end of the payment to figure out no items were in stock.
Instead I would use an "event-listener" using jQuery or Javascript or a PHP library to insure that during the checkout process if something in the database changed then the UI would indicate to the user the stock was different or unavailable.
回答4:
I think your problem is independent from your payment provider. It's your shop logic. I would do the following:
- User clicks on product to add to cart
- Product gets on an "in checkout" list and the number available in your shop get decreased by one
- Then we have two possibilities:
- User finishes the checkout with successful payment => you can keep the total amount of your products
- User aborts the checkout => you have to increase the total amount of your products after a specific time (eg. 5 minutes)
If you try to buy a seat in the cinema you have to finish the checkout in 5 minutes (count down is shown to user) otherwise the reservation is lost and someone else can book the seats.
回答5:
I would like to suggest another way to do this, this is the way in which we handle payments and inventory on our store. the main problem arises during high volume sales and we handled Black Friday and Cyber Monday sales with our inventory management solution.
You have to ensure following steps for concurrent payment
- You should check available stock just before the user is about to enter payment process. you can do this by keeping this data in Redis instead of querying the database every time. whenever an order is placed it will update the stock entries in Redis to be in sync.
- when you are about to call payment gateway for payment check for available stock and process ahead if available otherwise prompt user.
- When a user completes payment deduct purchased quantity from inventory in database transaction and using the lock. if transaction not succeed either refund the payment or it's up to you want to make order for out of stock product or not.
Hope this helps you.
来源:https://stackoverflow.com/questions/48067837/should-i-use-a-queueing-system-to-handle-payments