1

I've read that Django > 1.9 introduces transaction.on_commit in order to avoid race conditions. I know that Django sets database autocommit to true by default, so each query becomes a transaction at db level.

However, take this example,

from django.db import transaction

def some_view(request):
    obj = SomeModel.objects.create(field=value)
    transaction.on_commit(lambda: some_async_task(obj.pk))

Why should I wrap some_async_task(obj.pk) inside transaction.on_commit? I'm not sure how transactions work behind the scenes. All this time I've been thinking that as autocommit is enabled, create or save method should be a transaction itself, and then, in the next statement that object should exist in database.

whitenoisedb
  • 181
  • 9
  • Not all project use default autocommit. And some views can be decorated to be run in transaction / manually managed. – falsetru Jun 06 '17 at 05:41
  • Also according to [the documentation](https://docs.djangoproject.com/en/1.11/topics/db/transactions/#django.db.transaction.on_commit), `If you call on_commit() while there isn’t an active transaction, the callback will be executed immediately.`. So there's no harm to use `transaction.on_commit`. – falsetru Jun 06 '17 at 05:42
  • For example, it happened to me that inside a post_save I triggered a task sending instance pk. Then inside the task tried to retrieve the instance by its pk and failed because the transaction hadn't been commited yet. If it's autocommit enabled, why isn't the object commited into db just after save()? – whitenoisedb Jun 06 '17 at 06:09
  • Check this answer out: https://stackoverflow.com/a/33192224/2225682 – falsetru Jun 06 '17 at 06:15

1 Answers1

0

Ok. I've found the issue. I actually haven't explained the whole thing. Autocommit mode works right. It commits instantly, except when there's an active transaction.

I've realized I only expirienced this in Django's admin. The add/change views are wrapped inside a transaction. SO, my code inside post_save signal was triggered inside and the admin's save transaction wasn't finished yet.

That's why it makes sense to use transaction.on_commit anyway (added in Django > 1.9), because in this case its argument function would be triggered after outer transaction ends.

I'm using Django 1.6.5 but this also happens in 1.11

Hope this helps someone else.

whitenoisedb
  • 181
  • 9