Fix celery progress: assign state/info once to avoid race-conditions (#2142)

This commit is contained in:
Richard Schreiber
2021-07-05 15:09:47 +02:00
committed by GitHub
parent 9f6ce81229
commit 2e29e369f5

View File

@@ -24,6 +24,7 @@ from importlib import import_module
import celery.exceptions import celery.exceptions
import pytz import pytz
from celery import states
from celery.result import AsyncResult from celery.result import AsyncResult
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
@@ -61,7 +62,8 @@ class AsyncMixin:
return {} return {}
def _return_ajax_result(self, res, timeout=.5): def _return_ajax_result(self, res, timeout=.5):
if not res.ready(): ready = res.ready()
if not ready:
try: try:
res.get(timeout=timeout, propagate=False) res.get(timeout=timeout, propagate=False)
except celery.exceptions.TimeoutError: except celery.exceptions.TimeoutError:
@@ -75,7 +77,7 @@ class AsyncMixin:
}) })
return data return data
ready = res.ready() state, info = res.state, res.info
data = self._ajax_response_data() data = self._ajax_response_data()
data.update({ data.update({
'async_id': res.id, 'async_id': res.id,
@@ -83,32 +85,32 @@ class AsyncMixin:
'started': False, 'started': False,
}) })
if ready: if ready:
if res.successful() and not isinstance(res.info, Exception): if state == states.SUCCESS and not isinstance(info, Exception):
smes = self.get_success_message(res.info) smes = self.get_success_message(info)
if smes: if smes:
messages.success(self.request, smes) messages.success(self.request, smes)
# TODO: Do not store message if the ajax client states that it will not redirect # TODO: Do not store message if the ajax client states that it will not redirect
# but handle the message itself # but handle the message itself
data.update({ data.update({
'redirect': self.get_success_url(res.info), 'redirect': self.get_success_url(info),
'success': True, 'success': True,
'message': str(self.get_success_message(res.info)) 'message': str(self.get_success_message(info))
}) })
else: 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 # TODO: Do not store message if the ajax client states that it will not redirect
# but handle the message itself # but handle the message itself
data.update({ data.update({
'redirect': self.get_error_url(), 'redirect': self.get_error_url(),
'success': False, '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({ data.update({
'started': True, '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({ data.update({
'started': True, 'started': True,
}) })