龙卷风芹菜整合黑客

时间:2011-11-20 14:46:38

标签: python celery tornado

由于没有人提供this post的解决方案以及我迫切需要解决方法的事实,这里是我的情况和一些抽象的解决方案/想法供辩论。

我的筹码:

  1. 龙卷风
  2. 芹菜
  3. MongoDB的
  4. Redis的
  5. 的RabbitMQ
  6. 我的问题:为Tornado找一种方法来发送芹菜任务(已解决),然后异步收集结果(任何想法?)。

    场景1 :(请求/响应黑客加上webhook)

    • Tornado接收(用户)请求,然后在本地内存(或Redis)中保存{jobID :(用户)请求}以记住传播响应的位置,并使用jobID触发芹菜任务
    • 当芹菜完成任务时,它会在某个网址执行webhook并告诉龙卷风这个jobID已经完成(加上结果)
    • Tornado检索(用户)请求并将响应转发给(用户)

    这可能发生吗?它有任何逻辑吗?

    情景2 :(龙卷风加长轮询)

    • Tornado调度celery任务并将一些主json数据返回给客户端(jQuery)
    • jQuery在收到主json后进行一些长轮询,比方说,每x微秒,龙卷风根据某个数据库标志回复。当celery任务完成时,此数据库标志设置为True,然后jQuery“loop”结束。

    效率这么高吗?

    还有其他想法/架构吗?

4 个答案:

答案 0 :(得分:9)

我的解决方案涉及从龙卷风到芹菜的轮询:

class CeleryHandler(tornado.web.RequestHandlerr):

    @tornado.web.asynchronous
    def get(self):    

        task = yourCeleryTask.delay(**kwargs)

        def check_celery_task():
            if task.ready():
                self.write({'success':True} )
                self.set_header("Content-Type", "application/json")  
                self.finish()
            else:   
                tornado.ioloop.IOLoop.instance().add_timeout(datetime.timedelta(0.00001), check_celery_task)

        tornado.ioloop.IOLoop.instance().add_timeout(datetime.timedelta(0.00001), check_celery_task)

以下是post

答案 1 :(得分:8)

这是我们解决问题的方法。由于我们在应用程序中查找了几个处理程序的结果,因此我们将芹菜查找为mixin类。

这也使得tornado.gen模式的代码更具可读性。

from functools import partial

class CeleryResultMixin(object):
    """
    Adds a callback function which could wait for the result asynchronously
    """
    def wait_for_result(self, task, callback):
        if task.ready():
            callback(task.result)
        else:
            # TODO: Is this going to be too demanding on the result backend ?
            # Probably there should be a timeout before each add_callback
            tornado.ioloop.IOLoop.instance().add_callback(
                partial(self.wait_for_result, task, callback)
            )


class ARemoteTaskHandler(CeleryResultMixin, tornado.web.RequestHandler):
    """Execute a task asynchronously over a celery worker.
    Wait for the result without blocking
    When the result is available send it back
    """
    @tornado.web.asynchronous
    @tornado.web.authenticated
    @tornado.gen.engine
    def post(self):
        """Test the provided Magento connection
        """
        task = expensive_task.delay(
            self.get_argument('somearg'),
        )

        result = yield tornado.gen.Task(self.wait_for_result, task)

        self.write({
            'success': True,
            'result': result.some_value
        })
        self.finish()

答案 2 :(得分:4)

我偶然发现了这个问题,并且反复对结果进行后续检查对我来说并不是最佳选择。所以我使用Unix套接字实现了类似于你的场景1的Mixin。

一旦任务完成,它就会通知龙卷风(准确地说,只要链中的下一个任务运行),并且只会在后端点击一次结果。这是link

答案 3 :(得分:3)

现在,https://github.com/mher/tornado-celery来救援......

class GenAsyncHandler(web.RequestHandler):
    @asynchronous
    @gen.coroutine
    def get(self):
        response = yield gen.Task(tasks.sleep.apply_async, args=[3])
        self.write(str(response.result))
        self.finish()