Django using update() on bool column as an application operation lock
My Django app has an operation (syncing data from an external system) that I want to restrict from occuring twice simultaneously. For context, the data sync can occur due to a periodically scheduled task or due to the user manually/explicitly requesting a sync. If 2 sync jobs occur concurrently, the database may have an undesired state (and even trigger undesired effects in the application as a result). In the event that multiple syncs attempts occur concurrently, I would like 1 to succeed and the others to fail. The solution I have in mind is to have a boolean column called is_syncing
on my Tenant
model, since the data and logic for syncing pertains to the specific tenant. The idea is that before attempting an update, I would call
Tenant.objects.filter(id=tenant_id, is_syncing=False).update(is_syncing=True)
which will return the number of rows affected.
It should return 1
if is_syncing
was previously False
, meaning that the sync operation may occur. Or it may return 0
, meaning a sync has already begun and the application should abort/fail the sync attempt.
My questions are
- Will this approach avoid race conditions and guarantee no concurrent syncs?
- Is there a better way of going about this?
I am using Djangos default isolation level, which is READ_COMMITED
. I do not want to block reads during the sync, as the affected tables are frequently read. Of course, after a successful or failed sync, I would be setting the is_syncing
flag back to false.
I have tried this approach, but it is hard to be certain that it works in all cases.