race_conditions
Detects read-modify-write races, unsafe get_or_create, and select_for_update outside transactions in Django projects. Scans code to flag concurrency issues causing lost updates.
Instructions
Read-modify-save races, and row locks taken outside any transaction.
product = Product.objects.get(pk=pk)
product.stock -= quantity
product.save()
Two requests read 10, both subtract 3, both write 7; one sale is gone. A
transaction does not help, since neither sees the other's uncommitted
write. The fix is F("stock") - quantity so the database does the maths,
or select_for_update() inside atomic() to hold the row - and both of
those are silent here. Counters, balances, stock, retry counts: the
fields where off-by-one costs money.
Also: get_or_create() on a lookup no unique field, unique_together or
UniqueConstraint covers - two requests miss the get together, both
create, and the next call raises MultipleObjectsReturned. And
select_for_update() with no atomic() around it, which is not a race
but a TransactionManagementError the first time the line is reached.
Whether a transaction is open is judged with the call graph, so a caller's
atomic(), a decorator and ATOMIC_REQUESTS on a view all count.
Args:
search_path: directory to scan. Defaults to the project root.
include_parameters: also report mutations of an instance passed in
as a parameter, at medium confidence (the caller may hold a lock).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| search_path | No | ||
| include_parameters | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||