From 2e29e369f5295be004f9dd421bd92658ad15d0c9 Mon Sep 17 00:00:00 2001 From: Richard Schreiber Date: Mon, 5 Jul 2021 15:09:47 +0200 Subject: [PATCH] Fix celery progress: assign state/info once to avoid race-conditions (#2142) --- src/pretix/base/views/tasks.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/pretix/base/views/tasks.py b/src/pretix/base/views/tasks.py index 0c0514ce84..b3c391f877 100644 --- a/src/pretix/base/views/tasks.py +++ b/src/pretix/base/views/tasks.py @@ -24,6 +24,7 @@ from importlib import import_module import celery.exceptions import pytz +from celery import states from celery.result import AsyncResult from django.conf import settings from django.contrib import messages @@ -61,7 +62,8 @@ class AsyncMixin: return {} def _return_ajax_result(self, res, timeout=.5): - if not res.ready(): + ready = res.ready() + if not ready: try: res.get(timeout=timeout, propagate=False) except celery.exceptions.TimeoutError: @@ -75,7 +77,7 @@ class AsyncMixin: }) return data - ready = res.ready() + state, info = res.state, res.info data = self._ajax_response_data() data.update({ 'async_id': res.id, @@ -83,32 +85,32 @@ class AsyncMixin: 'started': False, }) if ready: - if res.successful() and not isinstance(res.info, Exception): - smes = self.get_success_message(res.info) + if state == states.SUCCESS and not isinstance(info, Exception): + smes = self.get_success_message(info) if smes: messages.success(self.request, smes) # TODO: Do not store message if the ajax client states that it will not redirect # but handle the message itself data.update({ - 'redirect': self.get_success_url(res.info), + 'redirect': self.get_success_url(info), 'success': True, - 'message': str(self.get_success_message(res.info)) + 'message': str(self.get_success_message(info)) }) else: - messages.error(self.request, self.get_error_message(res.info)) + messages.error(self.request, self.get_error_message(info)) # TODO: Do not store message if the ajax client states that it will not redirect # but handle the message itself data.update({ 'redirect': self.get_error_url(), 'success': False, - 'message': str(self.get_error_message(res.info)) + 'message': str(self.get_error_message(info)) }) - elif res.state == 'PROGRESS': + elif state == 'PROGRESS': data.update({ 'started': True, - 'percentage': res.result.get('value', 0) if isinstance(res.result, dict) else 0 + 'percentage': info.get('value', 0) if isinstance(info, dict) else 0 }) - elif res.state == 'STARTED': + elif state == 'STARTED': data.update({ 'started': True, })