Hi everyone,

I work on a medium-sized app where we might have tens of concurrent 
requests in flight at once. The application runs on Django 1.11, Python 3.5.

The problem I have is this: the web client requests to delete a record. On 
a successful delete, the app creates an "audit" record memorializing this 
delete, containing information about the record which was deleted. This is 
used in ETL jobs later. (I know there might be better ways of doing this 
sort of tracking, but I'm not looking to change that right now.)

Now, it's possible that, by toggling a button, the web client can send a 
stream of delete and create requests for this record. These may be received 
out-of-order by various server instances running in the cloud. So the 
following sequence (corresponding to CREATE -> DELETE -> CREATE -> DELETE) 
can happen:

   1. Request: Create record 1 for Server A 
   2. Request: Create record 1 for Server B
   3. Server A: Record 1 created, audit record cut
   4. Server B: No-op (Record 1 already exists)
   5. Request: Delete record 1 for Server A
   6. Request: Delete record 1 for Server B
   7. Server A: Record 1 deleted, audit record cut
   8. Server B: Record 1 deleted, audit record cut

This demonstrates that we may have 2 delete audit records for a single 
create audit record, which is just wrong. 

I tried a fix along the following lines:

records = Record.objects.filter(pk=...)
record = objects.first()
num_deleted, _ = records.delete()
if num_deleted == 1:
    Audit.objects.create_from_record(record) 

I had hoped this would work because, according to the Django docs, "The 
delete() is applied instantly.". 

However, I still seem to be able to trigger the race condition. 

I'm considering handling this on the frontend by queuing requests and 
waiting for the server to return a response before firing the next one, but 
it'd be nice to have a backend that can actually defend against this sort 
of thing. I'm also considering using a mutex, but it seems like Django 
should provide this functionality.

Wondering if anyone has suggestions around how to handle race conditions 
like this one. This can't be an uncommon problem, can it?

Any feedback is very much appreciated!

Thanks,
Ian

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/7438f2b4-9e47-4a1a-9087-667be14b027c%40googlegroups.com.

Reply via email to