暂停芹菜任务

时间:2018-01-24 21:07:16

标签: python flask celery

我试图根据用户点击按钮暂停芹菜任务。

我所做的是:

当用户点击按钮时;我发布了一个AJAX请求,将我的芹菜任务状态更新为" PAUSE"

然后;我的策略是;当我开始进入芹菜的任务;它运行for循环。 每个循环;我读了我的数据库' state'并查看它是否设置为PAUSE:如果设置为暂停;我想睡60秒或睡觉直到用户点击恢复按钮;同样的想法。

这是我的代码:

r  = redis.StrictRedis(host='localhost', port=6379, db=0)

@celery.task(bind=True)
def runTask(self, arr)

   for items in arr:
      current_task_id = self.request.id
      item = r.get('celery-task-meta-'+current_task_id)
      load_as_json = json.loads(item)
      if "PAUSE" in load_as_json['status']:
        sleep(50) 




@app.route('/start')
def start_task()
   runTask.apply_async(args=[arr])
   return 'task started running

以下是我的暂停API端点的样子:

@app.route('/stop/<task_id>')
def updateTaskState():
  task_id = request.cookie.get('task_id')
  loadAsJson = json.loads(r.get('celery-task-meta-'+str(task_id)))
  loadAsJson['status'] = 'PAUSE'
  loadAsJson.update(loadAsJson)
  dump_as_json = json.dumps(loadAsJson)
  updated_state = r.set('celery-task-meta-'+last_key, dump_as_json)
  return 'updated state';

从概念上理解;我没有看到更新状态的原因是因为;任务已执行,无法从数据库中检索更新的值。 仅供参考:任务更新状态立即设置为PAUSE;我通过创建一个单独的脚本来检查这一点,该脚本检查while循环中的状态;每次我点击释放AJAX请求的按钮来更新状态;我的数据库得到更新,它读取&#34; PAUSE&#34;在单独的脚本上;但是在@ celery.task装饰器中,我似乎无法获得更新状态。

下面是我用来测试的单独脚本;它似乎是按预期更新状态;我无法在任务装饰器中获得更新状态......很奇怪。

r  = redis.StrictRedis(host='localhost', port=6379, db=0)
last_key = r.keys()
while True:
    response = r.get('celery-task-meta-b1534a87-e18b-4f0a-89e2-08348d833056')
    loadAsJson = json.loads(response)
    print loadAsJson['status']

1 个答案:

答案 0 :(得分:0)

面对同样的问题,没有好的答案,我想出了您可能想要的解决方案,它不依赖于您正在使用的消息队列(aka Redis或RabbitMQ)。对我来说,关键是celery.app.task.Task类中的update_state方法将task_id作为可选参数。就我而言,我正在通过多个工作程序节点运行长时间运行的文件复制和校验和任务,有时用户希望暂停一项正在运行的任务,以降低对存储的性能要求,以允许其他任务先完成。我还正在运行无状态的Flask REST API,以启动后端任务并检索正在运行的任务的状态,因此我需要一种方法来调用API,以暂停和恢复任务。

这是我的测试功能,可以通过监视其自身状态来接收“消息”以暂停自身:

celery.task(bind=True)
def long_test(self, i):
    print('long test starting with delay of ' + str(i) + 'seconds on each loop')
    print('task_id =' + str(self.request.id))
    self.update_state(state='PROCESSING')
    count = 0
    while True:
        task = celery.AsyncResult(self.request.id)
        while task.state == 'PAUSING' or task.state == 'PAUSED':
            if task.state == 'PAUSING':
                self.update_state(state='PAUSED')
            time.sleep(i)
        if task.state == 'RESUME':
            self.update_state(state='PROCESSING')
        print('long test loop ' + str(count) + ' ' + str(task.state))
        count += 1
        time.sleep(i)

然后,为了暂停或继续,我可以执行以下操作:

>>> from project.celeryworker.tasks import long_test
>>> from project import create_app, make_celery
>>> flaskapp = create_app()
>>> celery = make_celery(flaskapp)
>>> from celery.app.task import Task
>>> long_test.apply_async(kwargs={'i': 5})
<AsyncResult: bf19d50f-cf04-47f0-a069-6545fb253887>
>>> Task.update_state(self=celery, task_id='bf19d50f-cf04-47f0-a069-6545fb253887', state='PAUSING')
>>> celery.AsyncResult('bf19d50f-cf04-47f0-a069-6545fb253887').state
'PAUSED'
>>> Task.update_state(self=celery, task_id='bf19d50f-cf04-47f0-a069-6545fb253887', state='RESUME')
>>> celery.AsyncResult('bf19d50f-cf04-47f0-a069-6545fb253887').state
'PROCESSING'
>>> Task.update_state(self=celery, task_id='bf19d50f-cf04-47f0-a069-6545fb253887', state='PAUSING')
>>> celery.AsyncResult('bf19d50f-cf04-47f0-a069-6545fb253887').state
'PAUSED'