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