#26627: outermost atomic block executes on_commit callbacks registered in 
another
outermost atomic block
----------------------------------------------+--------------------
     Reporter:  bartdag                       |      Owner:  nobody
         Type:  Bug                           |     Status:  new
    Component:  Database layer (models, ORM)  |    Version:  1.9
     Severity:  Normal                        |   Keywords:
 Triage Stage:  Unreviewed                    |  Has patch:  0
Easy pickings:  0                             |      UI/UX:  0
----------------------------------------------+--------------------
 The on_commit hook executes callbacks in an undesired order because the
 list of callbacks is tied to the connection instead of being tied to the
 transaction or atomic block. Consider the following code:

 {{{
 from django.db import transaction
 from foobar.models import Model1, Model2

 @transaction.atomic
 def outer():
     print("START - OUTER")
     for i in range(4):
         f1(i)
     print("END - OUTER")

 @transaction.atomic
 def f1(i):
     model = Model1(description="test {0}".format(i))
     model.save()
     transaction.on_commit(lambda: commit_hook(model, i))

 def commit_hook(model, i):
     print("START - on_commit hook")
     f2(i)
     print("STOP - on_commit hook")

 @transaction.atomic
 def f2(i):
     print("CALLING F2")
     model = Model2(description="test {0}".format(i))
     model.save()
 }}}

 The expected trace when calling outer() is:
 {{{
 START - OUTER
 END - OUTER
 START - on_commit hook
 CALLING F2
 STOP - on_commit hook
 START - on_commit hook
 CALLING F2
 STOP - on_commit hook
 START - on_commit hook
 CALLING F2
 STOP - on_commit hook
 START - on_commit hook
 CALLING F2
 STOP - on_commit hook
 }}}

 But the actual trace is:
 {{{
 START - OUTER
 END - OUTER
 START - on_commit hook
 CALLING F2
 START - on_commit hook
 CALLING F2
 START - on_commit hook
 CALLING F2
 START - on_commit hook
 CALLING F2
 STOP - on_commit hook
 STOP - on_commit hook
 STOP - on_commit hook
 STOP - on_commit hook
 }}}

 Essentially, the outermost atomic block on f2() is executing the callbacks
 registered by the outermost atomic block on outer(), which creates a stack
 of calls instead of a sequence of calls.

 This has been discussed on the [https://groups.google.com/forum/#!topic
 /django-users/e2lbYGqKszo Django user list] and more examples of why this
 can lead to undesired behaviors are given there.

 Carl Meyer has suggested a fix. I'll provide a regression test and a fix
 today.

--
Ticket URL: <https://code.djangoproject.com/ticket/26627>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/050.0df4d2ab0ea75a8e645d2daa22be8986%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to