Transactional safety for manual handling of sync jobs

This commit is contained in:
Raphael Michel
2025-08-08 09:21:05 +02:00
parent 38b9457e28
commit 2ac8f4bba7

View File

@@ -23,6 +23,7 @@
from itertools import groupby from itertools import groupby
from django.contrib import messages from django.contrib import messages
from django.db import transaction
from django.db.models import Q from django.db.models import Q
from django.dispatch import receiver from django.dispatch import receiver
from django.http import HttpResponseNotAllowed from django.http import HttpResponseNotAllowed
@@ -42,6 +43,7 @@ from pretix.control.permissions import (
) )
from pretix.control.signals import order_info from pretix.control.signals import order_info
from pretix.control.views.orders import OrderView from pretix.control.views.orders import OrderView
from pretix.helpers import OF_SELF
@receiver(order_info, dispatch_uid="datasync_control_order_info") @receiver(order_info, dispatch_uid="datasync_control_order_info")
@@ -79,14 +81,20 @@ class ControlSyncJob(OrderView):
prov.enqueue_order(self.order, 'user') prov.enqueue_order(self.order, 'user')
messages.success(self.request, _('The sync job has been enqueued and will run in the next minutes.')) messages.success(self.request, _('The sync job has been enqueued and will run in the next minutes.'))
elif self.request.POST.get("cancel_job"): elif self.request.POST.get("cancel_job"):
job = self.order.queued_sync_jobs.get(pk=self.request.POST.get("cancel_job")) with transaction.atomic():
job = self.order.queued_sync_jobs.select_for_update(of=OF_SELF).get(
pk=self.request.POST.get("cancel_job")
)
if job.in_flight: if job.in_flight:
messages.warning(self.request, _('The sync job is already in progress.')) messages.warning(self.request, _('The sync job is already in progress.'))
else: else:
job.delete() job.delete()
messages.success(self.request, _('The sync job has been canceled.')) messages.success(self.request, _('The sync job has been canceled.'))
elif self.request.POST.get("run_job_now"): elif self.request.POST.get("run_job_now"):
job = self.order.queued_sync_jobs.get(pk=self.request.POST.get("run_job_now")) with transaction.atomic():
job = self.order.queued_sync_jobs.select_for_update(of=OF_SELF).get(
pk=self.request.POST.get("run_job_now")
)
if job.in_flight: if job.in_flight:
messages.success(self.request, _('The sync job is already in progress.')) messages.success(self.request, _('The sync job is already in progress.'))
else: else: