调用挂在 Heroku 环境中的 celery 任务

Posted

技术标签:

【中文标题】调用挂在 Heroku 环境中的 celery 任务【英文标题】:Calling a celery task hanging in Heroku environment 【发布时间】:2013-06-24 15:41:23 【问题描述】:

我在 Heroku 上有一个 Django 应用程序,它使用 Celery 的 delay 方法调用任务,该方法应该将额外的处理传递给工作人员。但是当我向相应的视图发出 http 请求时,Heroku web dyno 挂起并最终导致请求超时。这是一个测试任务(应用程序称为等待时间):

@task
def test_tasks(message, name='waittimes.tasks.test_tasks'):
    print message

以及测试视图:

class TaskTest(View):
    def get(self, request):
        print "about to call the task"
        test_tasks.delay("the task was successful!")
        return HttpResponse("view was successful")

如果我向这个视图发出一个 http 请求,我希望“任务成功”会输出到控制台,并会得到一个“视图成功”的响应。当我向计算机上的开发服务器发出请求时,这会成功发生。如果我在我的应用程序的 Heroku 环境中启动 django shell 并使用 django 的测试客户端发出请求,它也可以工作。

app[celeryd.1]: [2013-06-26 23:57:48,018: INFO/MainProcess] Got task from broker: waittimes.tasks.test_tasks[67036069-b49e-45ba-aef4-3c64d7161a67]
app[celeryd.1]: [2013-06-26 23:57:48,133: WARNING/PoolWorker-3] the task was successful!
app[celeryd.1]: [2013-06-26 23:57:48,200: INFO/MainProcess] Task waittimes.tasks.test_tasks[67036069-b49e-45ba-aef4-3c64d7161a67] succeeded in 0.09690284729s: None

但是当我直接向 Heroku url 发出请求时,请求挂起,我最终从 Heroku 收到一个可怕的 H12 超时错误。

heroku[router]: at=error code=H12 desc="Request timeout" method=GET path=/task/test/ dyno=web.1 connect=2ms service=30000ms status=503 bytes=0

我知道调用任务会导致问题,因为“即将调用任务”确实会打印在控制台中。所以问题是系统无法解决“延迟”(和apply_async)方法。它只是挂起并且不返回异步对象。而且这只发生在代码在 web dyno 进程上运行时。

到目前为止,这些是我的结论:

1) 任务已正确注册并且我的 Redis 代理正在工作,因为当我使用测试客户端从 shell 调用视图时一切正常(但是这是在 Heroku 上的单独 shell 进程上运行,而不是在 web dyno 上运行通常接收请求)

2) 系统正确路由和分派请求的处理程序,因为“即将调用任务”被打印出来。 Heroku 路由器似乎没有问题。

3) 问题与特定视图无关,因为即使是这样的精简测试用例也不起作用

除了直接的解决方案,任何关于如何进一步调试的建议也值得赞赏。

【问题讨论】:

您找到解决方案了吗?我面临着完全相同的问题。 我假设你有 redis.TimeoutError 但你的 Http 服务器有更少的超时并且你首先看到它。你检查过这个理论吗?或者问题已经解决了? 【参考方案1】:

好吧,这可能不是一个直接的答案,但考虑到这个问题的年龄以及无人看管的持续时间,我会继续为其他不幸遇到这个问题的人提供我的见解。 /p>

这个特殊的问题似乎没有很好的文档记录并且很难搜索,我只是在云雀上在 Heroku 上建立一个辅助项目时遇到了它。

Heroku 似乎有一些地方性,其中某些 Python 函数调用在平台上的行为不同于本地(或在任何正常的 Python 部署中)。

就我而言,这里的问题是我的 Celery 任务正在调用 Python 的 time.sleep() 函数。

作为一个测试用例,我使用time.sleep(1) 只是为了在日志中证明该任务确实是异步执行的。我已经在普通基础架构(包括虚拟机)上多次成功运行了这个测试。

当我将此测试移植到 Heroku 时,我遇到了与 gentro 完全相同的问题。日志清楚地表明 Celery 和我的代理已正常初始化,并且知道我的应用程序,但是,当我通过 Django 视图进行调用时,我的 web dyno 会神秘地超时,H12 作为唯一的日志消息。

当我注释掉sleep 调用时,一切正常。

TL;DR - 检查导致 celery 任务的调用堆栈,确保没有留下任何可能导致 Heroku dyno 卡住的函数,例如 sleep()

我并不是说这就是导致原始提问者问题的具体原因,但如果您看到这种行为,这绝对是潜在原因之一。

【讨论】:

以上是关于调用挂在 Heroku 环境中的 celery 任务的主要内容,如果未能解决你的问题,请参考以下文章

celery multi 在heroku上崩溃

如何在heroku服务器中配置django-celery

Heroku 上未使用 Celery RabbitMQ CloudAMQP 任务队列

当客户端连接不稳定时,在 heroku 上运行的 django 中的工作人员会挂在帖子上

Heroku + Celery - 拒绝连接

Heroku/Celery:一名工人同时执行任务?