Python 芹菜使链条停止运转
我有一个定期执行的检查订单任务。它创建了一组任务,这样我就可以计算执行任务所花的时间,并在任务全部完成时执行某些操作(这是res.join[1]和grouped_subs的目的)分组的任务是成对的链式任务 我想要的是当第一个任务不满足条件(失败)时,不要执行链中的第二个任务。我一辈子都搞不懂这一点,我觉得这是作业队列管理器的基本功能。当我尝试在[2]之后注释掉的东西时(引发异常、删除回调)。。。由于某种原因,我们在check_orders中被join()卡住了(它破坏了组)。对于所有这些任务,我也尝试将ignore_result设置为False,但仍然不起作用Python 芹菜使链条停止运转,python,celery,django-celery,celery-task,celerybeat,Python,Celery,Django Celery,Celery Task,Celerybeat,我有一个定期执行的检查订单任务。它创建了一组任务,这样我就可以计算执行任务所花的时间,并在任务全部完成时执行某些操作(这是res.join[1]和grouped_subs的目的)分组的任务是成对的链式任务 我想要的是当第一个任务不满足条件(失败)时,不要执行链中的第二个任务。我一辈子都搞不懂这一点,我觉得这是作业队列管理器的基本功能。当我尝试在[2]之后注释掉的东西时(引发异常、删除回调)。。。由于某种原因,我们在check_orders中被join()卡住了(它破坏了组)。对于所有这些任务,我
@task(ignore_result=True)
def check_orders():
# check all the orders and send out appropriate notifications
grouped_subs = []
for thingy in things:
...
grouped_subs.append(chain(is_room_open.subtask((args_sub_1, )),
notify.subtask((args_sub_2, ), immutable=True)))
res = group(grouped_subs).apply_async()
res.join() #[1]
logger.info('Done checking orders at %s' % current_task.request.id))
@task(ignore_result=True)
def is_room_open(args_sub_1):
#something time consuming
if http_req_and_parse(args_sub_1):
# go on and do the notify task
return True
else:
# [2]
# STOP THE CHAIN SOMEHOW! Don't execute the rest of the chain, how?
# None of the following things work:
# is_room_open.update_state(state='FAILURE')
# raise celery.exceptions.Ignore()
# raise Exception('spam', 'eggs')
# current_task.request.callbacks[:] = []
@task(ignore_result=True)
def notify(args_sub_2):
# something else time consuming, only do this if the first part of the chain
# passed a test (the chained tasks before this were 'successful'
notify_user(args_sub_2)
首先,如果函数中存在异常
ignore\u result
似乎对您没有帮助
其次,您使用immutable=True,这意味着下一个函数(在我们的例子中是notify)不接受额外的参数。当然,如果适合您的决定,您应该使用notify.subtask((args\u sub\u 2,),immutable=False)
第三,您可以使用快捷方式:
notify.si(args\u sub\u 2)
而不是notify.subtask((args\u sub\u 2,),immutable=True)
及
是开着的房间吗.s(args\u sub\u 1)
相反是开着的房间吗.subtask((args\u sub\u 1,)
尝试使用it代码:
如果要捕获异常,则必须使用回调
文件室是否打开.s(args\u sub\u 1,link\u error=log\u error.s())
在我看来,这是一个在文档中没有得到足够重视的常见用例 假设您希望中途中止链,同时仍将成功报告为已完成任务的状态,并且不发送任何错误日志或诸如此类的内容(否则您可以引发异常),则实现此目的的方法是:
@app.task(bind=True) # Note that we need bind=True for self to work
def task1(self, other_args):
#do_stuff
if end_chain:
self.request.callbacks = None
return
#Other stuff to do if end_chain is False
在你的例子中:
@app.task(ignore_result=True, bind=True)
def is_room_open(self, args_sub_1):
#something time consuming
if http_req_and_parse(args_sub_1):
# go on and do the notify task
return True
else:
self.request.callbacks = None
会有用的。请注意,您可以使用@abbasov alexander所述的快捷方式.si()
,而不是ignore\u result=True
和subtask()
按照@PhilipGarnero在评论中的建议,编辑为使用急切模式工作。这令人难以置信,因为如此常见的情况在任何官方文件中都没有处理。我不得不处理同样的问题(但是使用
共享_任务和绑定选项,这样我们就可以看到self
对象),因此我编写了一个自定义装饰程序,自动处理撤销:
def revoke_chain_authority(a_shared_task):
"""
@see: https://gist.github.com/bloudermilk/2173940
@param a_shared_task: a @shared_task(bind=True) celery function.
@return:
"""
@wraps(a_shared_task)
def inner(self, *args, **kwargs):
try:
return a_shared_task(self, *args, **kwargs)
except RevokeChainRequested, e:
# Drop subsequent tasks in chain (if not EAGER mode)
if self.request.callbacks:
self.request.callbacks[:] = []
return e.return_value
return inner
您可以按如下方式使用它:
@shared_task(bind=True)
@revoke_chain_authority
def apply_fetching_decision(self, latitude, longitude):
#...
if condition:
raise RevokeChainRequested(False)
请参阅完整的解释。
希望有帮助 谢谢你提供的关于快捷方式的提示。虽然这会奏效,但并不能解决我的问题。如果第一个任务失败,我希望第二个任务永远不要执行。此解决方案仍然存在每次启动第二个任务的开销,与第一个任务的结果无关。我想停止执行锁链,我明白你的意思。如果任务引发异常,则链的执行将停止。它的行为是默认的。您不需要搜索特殊决策。@Alexander,引发异常无法正常工作。“当我尝试在[2]之后注释掉的内容时(引发异常、删除回调)…我们会因为某种原因在检查顺序中陷入join()状态(它会中断组)。”如果您在急切模式下运行任务,上述操作将停止任务。我将self.request.callbacks[:]=[]
替换为self.request.callbacks=None
,现在它在两种情况下都能工作。如果它在两种情况下都能工作,那么我们建议这样做。感谢您的评论,以改进答案:)显然,它不再适用于芹菜4.0,但是self.request.chain=None
可以。self.request.callbacks=None和self.request.chain=None对我都不起作用。我通过返回一个布尔值来解决这个问题,该布尔值指示是否应该中止,并在链的后续任务中接受它作为参数。谢谢。非常好的解决方案。现在看来callbacks
变量是一个元组,因此在尝试执行该操作时返回一个错误:self.request.callbacks[:]=[]''换行符''类型错误:'tuple'对象不支持芹菜4.0的项目分配
,您可以使用此答案-这是否回答了您的问题?
def revoke_chain_authority(a_shared_task):
"""
@see: https://gist.github.com/bloudermilk/2173940
@param a_shared_task: a @shared_task(bind=True) celery function.
@return:
"""
@wraps(a_shared_task)
def inner(self, *args, **kwargs):
try:
return a_shared_task(self, *args, **kwargs)
except RevokeChainRequested, e:
# Drop subsequent tasks in chain (if not EAGER mode)
if self.request.callbacks:
self.request.callbacks[:] = []
return e.return_value
return inner
@shared_task(bind=True)
@revoke_chain_authority
def apply_fetching_decision(self, latitude, longitude):
#...
if condition:
raise RevokeChainRequested(False)