TLDR;
要为celery生成的每个进程运行初始化函数,可以使用worker_process_init
信号。正如您可以在docs中读到的那样,该信号的处理程序不应该阻塞超过4秒。
但是有什么选择,如果我必须运行一个执行时间超过4秒的init函数?
问题
我使用C扩展模块在芹菜任务中运行某些操作。此模块需要初始化,可能需要几秒钟(可能是4-10)。因为我宁愿不为每个任务运行这个init函数,但对于每个生成的进程,我都使用了worker_process_init
信号:
#lib.py
import isclient #c extension module
client = None
def init():
global client
client = isclient.Client() #this might take a while
def create_ne_list(text):
return client.ne_receiventities4datachunk(text)
#celery.py
from celery import Celery
from celery.signals import worker_process_init
from lib import init
celery = Celery(include=[
'isc.ne.tasks'
])
celery.config_from_object('celeryconfig')
@worker_process_init.connect
def process_init(sender=None, conf=None, **kwargs):
init()
if __name__ == '__main__':
celery.start()
#tasks.py
from celery import celery
from lib import create_ne_list as cnl
@celery.task(time_limit=1200)
def create_ne_list(text):
return cnl(text)
当我运行此代码时,我在前面的问题(Celery: stuck in infinitly repeating timeouts (Timed out waiting for UP message))中描述了什么。简而言之:由于我的init函数需要超过4秒,因此有时会发生工作人员被杀死并重新启动,并且在重启过程中会再次被杀死,因为这是4秒无响应后自动发生的事情。这最终导致无限重复的杀戮和重启过程。
另一种选择是使用信号worker_init
为每个工作人员仅运行一次init函数。如果我这样做,我会遇到一个不同的问题:现在排队的进程由于某种原因而卡住了。
当我以3的并发性启动工作者,然后发送几个任务时,前三个将完成,剩下的任务不会被触及。 (我假设它可能与事实有关,client
对象需要在多个进程之间共享,并且由于某些原因,C扩展不支持它。但说实话,我对muli处理相对较新,所以我可以猜测)
问题
所以,问题仍然存在:如何为每个进程运行一个超过4秒的init函数?有没有一种正确的方法可以做到这一点,那会是什么样的方式?
答案 0 :(得分:7)
Celery将init超时限制为4.0秒。 查看source code
要解决此限制,您可以考虑在创建芹菜应用之前对其进行更改
from celery.concurrency import asynpool
asynpool.PROC_ALIVE_TIMEOUT = 10.0 #set this long enough
请注意,没有用于更改此值的配置或设置。
答案 1 :(得分:0)
@changhwan 的 answer 不再是 celery 4.4.0 的唯一方法。这是为此功能添加配置选项的 pull request。
对于 celery ^4.4.0
,这个值是可配置的。使用 celery 应用程序配置选项 worker_proc_alive_timeout
。来自stable version docs:
worker_proc_alive_timeout
默认值:4.0。
等待新工作进程启动时的超时时间(整数/浮点数)。
from celery import Celery
from celery.signals import worker_process_init
app = Celery('app')
app.conf.worker_proc_alive_timeout = 10
@worker_process_init.connect
def long_init_function(*args, **kwargs):
import time
time.sleep(8)