Django select_for_update(nowait=False) in transaction.atomic() does not work as expected
I have a django app that needs to get a unique ID. Many threads run at the same time that need one. I would like the IDs to be sequential. When I need a unique ID I do this:
with transaction.atomic():
max_batch_id = JobStatus.objects.select_for_update(nowait=False).aggregate(Max('batch_id'))
json_dict['batch_id'] = max_batch_id['batch_id__max'] + 1
status_row = JobStatus(**json_dict)
status_row.save()
But multiple jobs are getting the same ID. Why does the code not work as I expect? What is a better way to accomplish what I need? I cannot use the row id as there are many rows that have the same batch_id.
As Django docs says in Docs, you can use F() for avoiding race condition:
The process can be made robust, avoiding a race condition, as well as slightly faster by expressing the update relative to the original field value, rather than as an explicit assignment of a new value. Django provides F expressions for performing this kind of relative update.
So you probably want sth like this:
...
max_batch_id = JobStatus.objects.select_for_update(nowait=False).aggregate(Max(F('batch_id')))
...