我有一个芹菜shared_task
设置,如果第一次没有成功,最多可以重试10次。初始日志语句仅执行一次。不会引发任何异常,嵌入式try/else
也不会引发异常。语句result = LdapHostGroupView().start(data, username, version)
确实执行了,并且从日志条目中显示它已成功执行,但是最后一个else
从未执行。
这是怎么回事?
@shared_task(bind=True, default_retry_delay=15, max_retry=10)
def host_accepted(self, data, username, version):
from .api.views import LdapHostGroupView
name = data.get('name', '')
version = Decimal(version)
log.debug("name: %s, version: %s, version type: %s, data: %s",
name, version, type(version), data)
try:
obj = Transaction.objects.get(endpoint_name=name)
except Transaction.DoesNotExist as e:
msg = "Could not find transaction '{}'".format(name)
log.critical(msg)
syslog.critical(msg)
else:
try:
result = LdapHostGroupView().start(data, username, version)
except RealmBundleDoesNotExist as e:
log.debug("Bundle does not exist yet.")
obj.job_summary += str(e) + '\n'
obj.job_status = Transaction.INPROGRESS
obj.save()
self.retry(exc=e) # ** self.request.retries)
except (RealmCriticalException, ValidationError) as e:
error = e.get_full_details()
log.debug("Host Accepted error: %s", error)
if isinstance(error, dict):
for field, values in error.items():
for value in values:
ed = value.get('message')
if isinstance(ed, ErrorDetail):
item = str(ed)
else:
item = value
msg = "Field '{}' has error: {}\n".format(field, item)
obj.job_summary += msg
else:
obj.job_summary += "Had error with no message.\n"
obj.job_status = Transaction.FAILURE
obj.save()
else:
log.info("Celery task 'host_accepted' executed at %s, "
"returned %s, incoming data %s",
datetime.now(tzutc()).isoformat(), result, data)
# Check the result object.
obj.job_status = Transaction.SUCCESS
obj.save()
在Django视图中这样调用它:
host_accepted.delay(request.data, request.user.username, request.version)
答案 0 :(得分:0)
因此,在发布我的问题后,我想到上面的代码依赖于我能够重新创建request
对象或腌制一个对象。这些方法都不可行。因此,我需要做的是仅包装这段代码,这些代码需要一段时间才能在celery任务中运行。我发现我可以用序列化器的create
方法(而不是普通的数据库对象)返回celery任务的结果。
我应该提到,此序列化器在任何情况下都不会返回DB对象,因为它实际上将来自两个外部API的数据聚合到我的API中。我没有显示该代码。
我的视图已经过大量自定义,但是它们几乎可以用作普通视图。
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__accepted = False
def post(self, request, *args, **kwargs):
self.__accepted = False # Use the normal serializer
self.create(request, *args, **kwargs)
self.__accepted = True # Use the JobQueue serializer
return self.create_accepted(request, *args, **kwargs)
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
# Do not return a Response
def create_accepted(self, request, *args, **kwargs):
data = {}
data['endpoint_name'] = request.data.get('name')
# Add any data needed to create a JobQueue object.
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
data = serializer.data
headers = self.get_success_headers(data)
return Response(data, status=status.HTTP_202_ACCEPTED,
headers=headers)
def get_serializer_class(self):
serializer = None
if self.__accepted:
if self.request.version == Decimal("1"):
serializer = JobQueueSerializerVer01
else:
if self.request.version == Decimal("1"):
serializer = SomeSerializerVer01
return serializer
现在序列化程序更改:
class SomeSerializerVer01(serializers.Serializer):
def create(self, validated_data):
# Call the task
return wait_for_long_running_code.delay(
validated_data, self.initial_data)
def create_after_task(self, validated_data, initial_data):
self.initial_data = initial_data
self._create_or_update_job_queue(
name, job_status=JobQueue.INPROGRESS)
# Do what you need to do here
data = {}
# Update the JobQueue DB object.
self._create_or_update_job_queue(
name, job_status=JobQueue.SUCCESS,
job_ended=datetime.datetime.now(tzutc()))
return data
def _create_or_update_job_queue(self, name, **kwargs):
trx = JobQueue.objects.create_transaction(
name, Endpoint.HOST_GROUP, self.get_user_object(), **kwargs)
return trx
现在执行任务:
@shared_task(bind=True, default_retry_delay=15, max_retry=8)
def wait_for_long_runninf_code(self, validated_data, initial_data):
from your.path import SomeSerializerVer01
ser = SomeSerializerVer01()
result = {}
try:
result = ser.create_after_task(validated_data, initial_data)
except Exception:
self.retry(exc=e)
return result
就是这样。我所做的某些事情可能不需要通过initial_data
字典来完成。上面没有显示所有内容,例如JobQueue
数据库对象的视图和序列化程序。