我有一个服务,该服务公开一个API,然后该API负责执行任务,它是通过Falcon(API)和Celery(任务管理)实现的。
具体来说,我的工作人员需要很长时间才能加载,并且他们的代码看起来像这样
class HeavyOp(celery.Task):
def __init__(self):
self._asset = get_heavy_asset() # <-- takes long time
@property
def asset(self):
return self._asset
@app.task(base=HeavyOp)
def my_task(data):
return my_task.asset.do_something(data)
实际发生的情况是,在__init__
函数中,从磁盘读取某些对象并将其保存在内存中的时间,直到工作人员生存为止。
有时候,我想更新该对象。
有没有一种方法可以在不停机的情况下重新加载工作程序?由于这都是API的背后功能,所以我不希望花这么几分钟来加载重对象作为停机时间。
我们可以假设主机具有1个以上的内核,但是解决方案必须是单个主机解决方案。
答案 0 :(得分:0)
我认为您不需要自定义基本任务类。您想要实现的是一个单实例资产类,该类将在工作人员初始化之后加载,您可以从任务中重新加载。
此方法有效:
# worker.py
import os
import sys
import time
from celery import Celery
from celery.signals import worker_ready
app = Celery(include=('tasks',))
class Asset:
def __init__(self):
self.time = time.time()
class AssetLoader:
__shared_state = {}
def __init__(self):
self.__dict__ = self.__shared_state
if '_value' not in self.__dict__:
self.get_heavy_asset()
def get_heavy_asset(self):
self._value = Asset()
@property
def value(self):
return self._value
@worker_ready.connect
def after_worker_ready(sender, **kwargs):
AssetLoader()
在这里,我使AssetLoader成为Borg类,但是您可以选择任何其他模式/策略来共享Asset的单个实例。出于说明目的,我只捕获了执行get_heavy_asset
时的时间戳。
# tasks.py
from worker import app, AssetLoader
@app.task(bind=True)
def load(self):
AssetLoader().get_heavy_asset()
return AssetLoader().value.time
@app.task(bind=True)
def my_task(self):
return AssetLoader().value.time
请记住,资产是按工作人员进程共享的,但不能跨工作人员共享。如果您使用concurrency=1
进行运行,则没有任何区别,但是对于其他任何事情,它都可以。但是从我收集到的用例来看,无论哪种方式都应该很好。