mirror of
https://github.com/pretix/pretix.git
synced 2026-05-05 15:14:04 +00:00
Transactiontask (#268)
* Introduce TransactionAwareTask As described in https://blog.hypertrack.io/2016/10/08/dealing-with-database-transactions-in-django-celery/ * Use TransactionAwareTask instead of countdown … to prevent race conditions when using a newly created object in a task.
This commit is contained in:
committed by
Raphael Michel
parent
6c5cd56af7
commit
9db333bf80
28
src/pretix/base/services/async.py
Normal file
28
src/pretix/base/services/async.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
"""
|
||||||
|
This code has been taken from
|
||||||
|
https://blog.hypertrack.io/2016/10/08/dealing-with-database-transactions-in-django-celery/
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
from pretix.base.services.async import TransactionAwareTask
|
||||||
|
@task(base=TransactionAwareTask)
|
||||||
|
def task_…():
|
||||||
|
"""
|
||||||
|
from celery import Task
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
|
|
||||||
|
class TransactionAwareTask(Task):
|
||||||
|
"""
|
||||||
|
Task class which is aware of django db transactions and only executes tasks
|
||||||
|
after transaction has been committed
|
||||||
|
"""
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
def apply_async(self, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Unlike the default task in celery, this task does not return an async
|
||||||
|
result
|
||||||
|
"""
|
||||||
|
transaction.on_commit(
|
||||||
|
lambda: super(TransactionAwareTask, self).apply_async(*args, **kwargs)
|
||||||
|
)
|
||||||
@@ -23,6 +23,7 @@ from reportlab.platypus import (
|
|||||||
|
|
||||||
from pretix.base.i18n import LazyI18nString, language
|
from pretix.base.i18n import LazyI18nString, language
|
||||||
from pretix.base.models import Invoice, InvoiceAddress, InvoiceLine, Order
|
from pretix.base.models import Invoice, InvoiceAddress, InvoiceLine, Order
|
||||||
|
from pretix.base.services.async import TransactionAwareTask
|
||||||
from pretix.base.signals import register_payment_providers
|
from pretix.base.signals import register_payment_providers
|
||||||
from pretix.celery import app
|
from pretix.celery import app
|
||||||
|
|
||||||
@@ -375,7 +376,7 @@ def _invoice_generate_german(invoice, f):
|
|||||||
return doc
|
return doc
|
||||||
|
|
||||||
|
|
||||||
@app.task
|
@app.task(base=TransactionAwareTask)
|
||||||
def invoice_pdf_task(invoice: int):
|
def invoice_pdf_task(invoice: int):
|
||||||
i = Invoice.objects.get(pk=invoice)
|
i = Invoice.objects.get(pk=invoice)
|
||||||
with language(i.locale):
|
with language(i.locale):
|
||||||
@@ -394,7 +395,8 @@ def invoice_qualified(order: Order):
|
|||||||
|
|
||||||
|
|
||||||
def invoice_pdf(*args, **kwargs):
|
def invoice_pdf(*args, **kwargs):
|
||||||
# We introduce a 2 second delay, because otherwise we run into conditions where
|
# We call this task asynchroneously, because otherwise we run into conditions where
|
||||||
# the task worker tries to generate the PDF even before our database transaction
|
# the task worker tries to generate the PDF even before our database transaction
|
||||||
# was committed and therefore fails to find the invoice object.
|
# was committed and therefore fails to find the invoice object. The invoice_pdf_task
|
||||||
invoice_pdf_task.apply_async(args=args, kwargs=kwargs, countdown=2)
|
# will prevent this kind of race condition.
|
||||||
|
invoice_pdf_task.apply_async(args=args, kwargs=kwargs)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from django.utils.translation import ugettext_noop
|
|||||||
|
|
||||||
from pretix.base.i18n import language
|
from pretix.base.i18n import language
|
||||||
from pretix.base.models import Event, Order, Quota
|
from pretix.base.models import Event, Order, Quota
|
||||||
|
from pretix.base.services.async import TransactionAwareTask
|
||||||
from pretix.base.services.mail import SendMailException
|
from pretix.base.services.mail import SendMailException
|
||||||
from pretix.base.services.orders import mark_order_paid
|
from pretix.base.services.orders import mark_order_paid
|
||||||
from pretix.celery import app
|
from pretix.celery import app
|
||||||
@@ -95,7 +96,7 @@ def _get_unknown_transactions(event: Event, job: BankImportJob, data: list):
|
|||||||
return transactions
|
return transactions
|
||||||
|
|
||||||
|
|
||||||
@app.task
|
@app.task(base=TransactionAwareTask)
|
||||||
def process_banktransfers(event: int, job: int, data: list) -> None:
|
def process_banktransfers(event: int, job: int, data: list) -> None:
|
||||||
with language("en"): # We'll translate error messages at display time
|
with language("en"): # We'll translate error messages at display time
|
||||||
event = Event.objects.get(pk=event)
|
event = Event.objects.get(pk=event)
|
||||||
|
|||||||
@@ -337,7 +337,7 @@ class ImportView(EventPermissionRequiredMixin, ListView):
|
|||||||
'event': self.request.event.pk,
|
'event': self.request.event.pk,
|
||||||
'job': job.pk,
|
'job': job.pk,
|
||||||
'data': parsed
|
'data': parsed
|
||||||
}, countdown=1)
|
})
|
||||||
return redirect(reverse('plugins:banktransfer:import.job', kwargs={
|
return redirect(reverse('plugins:banktransfer:import.job', kwargs={
|
||||||
'event': self.request.event.slug,
|
'event': self.request.event.slug,
|
||||||
'organizer': self.request.event.organizer.slug,
|
'organizer': self.request.event.organizer.slug,
|
||||||
|
|||||||
Reference in New Issue
Block a user