我正在开发一个项目,其目标是运行一个守护进程,该守护进程将任务发送到Celery队列,Redis用作代理。每个任务必须一次处理一次(不允许并发)。
为了执行此操作,我将以下代码段实现到我的守护程序中,该守护程序充当Redis的锁:
while True:
for foo in bar:
if not self.redis_client.exists(foo.name):
# Send the task to the Celery queue
task = celery_app.send_task('buzz', context={'name': foo.name})
redis_client.send(foo.name, task.id)
time.sleep(10)
一旦任务完成或失败,任务本身就会释放锁。
由于某些我不理解的原因,该任务有时会由两个工作进程同时运行:
[2018-04-11 15:23:45,705: INFO/ForkPoolWorker-1] Task has been executed in 101.43s for foo
[2018-04-11 15:23:45,881: INFO/ForkPoolWorker-4] Task has been executed in 114.66s for foo
它不会经常发生,但我不希望它发生。有什么可以解释这种行为?是否与Redis写入键/值对的开销时间有关?
作为附加信息,我还在同一台服务器上运行了一个Flower实例。
答案 0 :(得分:1)
这里有很多遗漏的细节,但我会尽力帮助:
由于你的要求 - 没有并发性 - 我猜你只有一个芹菜工人在运行。
运行此worker时,可以通过-c
标志(或--concurrency
)指定并发级别 - 确保将其设置为1,这样一次只能生成该worker的一个实例。 ref here
例如:celery -A proj worker --loglevel=INFO --concurrency=1 -n worker1@%h
您应该注意的另一件事是worker_prefetch_multiplier
,默认情况下一次预取4条消息。您可能也想将其更改为1(我猜您没有描述您的完整方案)。 ref here
最后,关于你的redis锁,考虑使用SETNX(如果不存在则设置) - 更多信息 - here
祝你好运!