﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
26627	outermost atomic block executes on_commit callbacks registered in another outermost atomic block	Barthelemy Dagenais	nobody	"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."	Bug	closed	Database layer (models, ORM)	1.9	Normal	fixed			Ready for checkin	1	0	0	0	0	0
