Let’s say I have a table called Withdrawals (id, amount, user_id, status).
Whenever I a withdrawal is initiated this is the flow:
- Verify if user has sufficient balance (which is calculated as sum of amount received - sum of withdrawals amount)
- Insert row with amount, user_id and status=‘pending’
- Call 3rd party software through gRPC to initiate a withdrawal (actually send money), wait for a response
- Update row with status = ‘completed’ as soon we a positive response or delete the entry if the withdrawal failed.
However, I have a concurrency problem in this flow. Let’s say the user makes 2 full balance withdrawal requests within ~50 ms difference:
Request 1
- User has enough balance
- Create Withdrawal (balance = 0)
- Update withdrawal status
Request 2 (after ~50ms)
- User has enough balance (which is not true, the other insert didn’t got stored yet)
- Create Withdrawal (balance = negative )
- Update withdrawal status
Right now, we are using redis to lock withdrawals to specific user if they are within x ms, to avoid this situation, however this is not the most robust solution. As we are developing an API for businesses right now, with our current solution, we would be blocking possible withdrawals that could be requested at the same time. Is there any way to lock and make sure consequent insert queries wait based on the user_id of the Withdrawals table ?