A small project showing serializable transactions usage and capability, made as part of the article It's not always about locking data. The goal of this project is to have a self-contained test showing a possible use-case of SERIALIZABLE Isolation Level.
This small app emulates a bank account withdrawal process.
This endpoint allows users to initiate a withdrawal request. If you pass serializable parameter as false (or don't pass it at all), the withdrawal request will be handled using READ COMMITED isolation level, which will fail validating the daily withdrawal limit of $5000 in case of two or more concurrent requests for same user. Otherwise, if you pass serializable as true, the request will be handle using SERIALIZABLE isolation level, protecting the database from an inconsistent state.
Be aware that this endpoint has a sleep of 5 seconds before committing changes on database. This is needed to reproduce the scenario without having a high load environment. You can check it at WithdrawalService.
POST
/withdrawals
serializable={false|true}
- Content-Type:
application/json
The request body should be a JSON object with the following fields:
{
"amount": 1000,
"user": 1
}Before you begin, make sure you have met the following requirements:
- NodeJS v18 or above
- Docker v27 or above
Clone this repo and issue a npm install command at the root directory to install its dependencies.
To run this project, you have two options: either start the application and send concurrent requests manually (in that case you also need a PostgreSQL instance running locally), or run the integration tests, which include this scenario and starts a PostgreSQL container automatically.
- Create a
.envfile and add your PostgreSQL URI there, such asDATABASE_URL=postgres://myuser:mypass@localhost:5432/mydatabase. - Issue a
npx sequelize-cli db:migrateto run all database migrations (create tables, etc.) - Now you're good to go, just issue a
npm startto start the app - Then you can send requests, e.g.:
curl --request POST \
--url 'http://localhost:3000/withdrawals?serializable=false' \
--header 'Content-Type: application/json' \
--data '{
"amount": 1000,
"user": 1
}'Remember to run at least 2 requests simultaneously for same user and to play with serializable query parameter.
- Issue a
npm testand inspect test results
We're covering these scenarios:
- Two concurrent requests for same user to be handled by
READ COMMITEDisolation level. This test is intentionally failing due to inability of applying the limit. - Two concurrent requests for same user to be handled by
SERIALIZABLEisolation level. This test is running fine.
This project is licensed under the GNU General Public License v3.0. See the LICENSE file for more details.
