簡體   English   中英

任務進度未更新Celery + RabbitMQ上的最新狀態

[英]Task progress is not updated latest status on Celery+RabbitMQ

我在Celery + RabbitMQ結果后端上使用自定義狀態實現了長期任務的進度反饋。

但是呼叫者無法按我期望的那樣獲取最新的進度狀態。 在以下代碼中, result.info['step'] 始終返回0 ,然后任務將以“ result = 42”結束。

# tasks.py -- celery worker
from celery import Celery
app = Celery('tasks', backend='amqp', broker='amqp://guest@localhost//')

@app.task
def long_task():
  for i in range(0, 10):
    timer.sleep(10)  # some work
    self.update_state(state='PROGRESS', meta={'step': i})
  return 42


# caller.py
from tasks import long_task
result = long_task.delay()

while not (result.successful() or result.failed()):
  try:
    result.get(timeout=1)
  except celery.exceptions.TimeoutError:
    if result.state == 'PROGRESS':
      print("progress={}".format(result.info['step']))
print("result={}".format(result.get()))

Python 3.4.1 /芹菜3.1.17 / RabbitMQ 3.4.4

我相信這是一個細微的計時問題,再加上RabbitMQ結果后端將任務結果作為消息發送,並且只能被檢索一次的事實。

預先簡短的答案:避免在真正需要最終結果之前調用result.get()

while not result.ready():
  if result.state == "PROGRESS":
    print("progress={}".format(result.info['step']))
  time.sleep(1)
print("result={}".format(result.get()))
# +additional cleanup: see comments below

更長的答案是,這里實際上有兩種與AMQP后端對話的方法(和屬性):

  • AsyncResult.get()

    調用AMQPBackend.wait_for() ,它將消耗任務隊列中的所有結果,直到出現狀態為celery.states.READY_STATES的結果為止。

  • AsyncResult.successful()AsyncResult.failed()AsyncResult.info

    調用AMQPBackend.get_task_meta() ,它將使用任務隊列中的所有結果,然后進行緩存並返回最新的結果。 如果未檢索到任何消息,則后端將返回緩存的結果或PENDING結果。 注意:最新消息由后端重新排隊 ,如果是最終結果 ,它將由AsyncResult實例1緩存。

調用result.get()將消耗所有狀態更新,而result.info沒有機會提供最新進度報告; 取而代之的是,它很可能是一個過時的緩存,它在某個時候成功捕獲了對AsyncResult.get_task_meta()的調用之一。

因此,根據時間安排,在次最差情況下, step可能會停留在0,最差的情況是PROGRESS狀態永遠不會到達調用者。

1因為通過調用get_task_meta()來獲取最終結果時,它既要重新排隊get_task_meta()緩存,所以您需要按照以下注釋中的說明手動排空隊列。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM