Imagine you're at the theater. You have one coat and one ticket. You approach the cloakroom counter, hand over your ticket, and at the same moment, your friend (to whom you gave a photocopy of your ticket) runs to another window and also hands over their ticket.
If the cloakroom attendants don't work together, they might both look at the ticket, both go looking for your coat, and one of them gives it to you, and the other to your friend. The result: one coat, one ticket, but two people got the item.
In programming, this is called a race condition.
This is a situation where the outcome of a program depends on the order in which parallel processes are executed. If two requests enter the system simultaneously and operate on the same data, they can corrupt that data.
A classic example is debiting funds from a balance:
Request A: "How much money does Vasya have?" -> Server: "100 rubles."
Request B: "How much money does Vasya have?" -> Server: "100 rubles" (because A hasn't yet debited the balance).
Request A: "Debit 100 rubles" -> Success.
Request B: "Debit 100 rubles" -> Success (because the check was done earlier).
Result: Vasya received 200 rubles in payments, even though he only had 100. You're in losses.
Both requests were based on outdated information. They weren't aware of each other's existence. This is a race—both are racing to get the data, and whoever gets there first wins, often at the cost of system integrity.
APIs (especially REST) usually operate over HTTP. They're stateless. This means the server has processed the request and forgotten about it.
If 10 requests come in simultaneously, the server can start processing them in 10 different threads. Each thread reads the balance, decides, "OK, there's enough money," and debits it. They don't know about each other. This is the perfect environment for race conditions.
In high-load systems, where thousands of transactions involving wallets, orders, tickets, or any other limited resources are processed simultaneously, the likelihood of race conditions increases dramatically. Even if the code is written correctly from the perspective of the logic of a single request, parallel execution can ruin the whole picture.
While developing RK-CMS, we've encountered the consequences of race conditions many times: duplicate write-offs, incorrect inventory balances, duplicate orders. We understand how insidious this problem can be: it doesn't always manifest itself, but only under certain circumstances—for example, under high load or during peak loads.
That's why we consider race protection a mandatory part of our architecture, not an optional feature. We know how to combat it and use proven mechanisms that prevent two concurrent requests from corrupting data.