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 binnenon_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.
댓글이 없습니다.