1. Probleem: wordt on_commit() te snel uitgevoerd?

Recentelijk heb ik in een Django-project transaction.on_commit() gebruikt om
Celery-taken pas na een succesvolle transactie uit te voeren.

Maar toen ik de logs bekeek, gebeurde er iets vreemds.

Zelfs voordat taken zoals post.categories.add(...) waren voltooid,
werd de Celery-taak binnen on_commit() uitgevoerd.


2. Als ik naar de code kijk…

def view():
    post = Post.objects.create(...)

    def post_process():
        with transaction.atomic():
            post.categories.add(...)
            post.tags.add(...)

            def run_async():
                translate_post.delay(post.id)

            transaction.on_commit(run_async)

    threading.Thread(target=post_process).start()

In het begin leek er niets aan de hand…
maar deze threading.Thread() was de valkuil.


3. Oorzaak: transacties zijn thread-lokaal

De transacties in Django zijn afhankelijk van de huidige thread.
Dat wil zeggen, transaction.atomic() en on_commit() zijn alleen van toepassing op de transacties die in deze thread zijn geopend.

Een transaction.atomic() in een nieuwe thread
heeft niets te maken met de hoofdtransactie.


4. Wat er uiteindelijk gebeurde

  • De Celery-taak werd "uitgevoerd na de transactiecommit", maar
  • deze transactie was slechts een beperkte subtransactie in de sub-thread
  • en post.categories.add(...) was nog steeds aan de gang

Dus, de Celery-taak werd te vroeg uitgevoerd,
waardoor er problemen ontstonden met verwijzing naar onvolledige gegevens.


5. Oplossing

Zo los je het eenvoudig op:

def view():
    post = Post.objects.create(...)

    with transaction.atomic():
        post.categories.add(...)
        post.tags.add(...)

        def run_async():
            translate_post.delay(post.id)

        transaction.on_commit(run_async)

🚫 threading.Thread(...)
✅ Gewoon on_commit() in de hoofdthread registreren


6. Samenvatting

  • Transacties in Django zijn thread-lokaal
  • on_commit() wordt alleen uitgevoerd na de transactiecommit in de huidige thread
  • Als je het in een andere thread registreert, reageert het alleen op die thread's transacties

Deze ervaring was een krachtige les.
Ik realiseerde me dat wanneer ik transacties + Celery + threads gebruik,
ik echt voorzichtig moet zijn.