我的芹菜任务是对某些数据库存储的实体进行耗时的计算。工作流程是这样的:从数据库获取信息,将其编译为可序列化的对象,然后保存对象。其他任务正在对加载的对象进行其他计算(例如渲染图像)。
但是序列化非常耗时,因此我希望每个实体运行一个任务一段时间,该任务将序列化的对象保存在内存中并处理通过消息传递队列(redis pubsub)传递的客户端请求。如果一段时间没有请求,则任务退出。此后,如果客户端需要完成一些工作,它将运行另一个任务,该任务将加载对象,对其进行处理并为其他任务保持一段时间。此任务应在启动时检查,如果该特定实体上只有一个工作线程,则应避免发生冲突。 那么最好的检查策略是为此实体运行另一个任务吗?
1)第一个想法是将消息发送到与实体关联的某个通道,并等待响应。不好的主意,目标任务可能会忙于计算,等待超时响应只是浪费时间。
2)将celery task-id存储在db中甚至更糟-可以杀死任务,但记录会保留,因此我们需要确保目标任务仍然存在。
3)第三个想法是检查工作程序中正在运行的任务,并检查其状态以获取实体ID(启动时将提供该任务)。似乎还可能会发生一些冲突,即如果计划了多个任务,但尚未运行。
就目前而言,我认为想法1最好是进行如下修改:任务将在启动时以启动时间将消息发送到实体通道,但随后立即开始工作,而不等待响应。然后,它检查消息队列,如果有人响应,他们将比较时间戳和退出较大的任务。似乎足够复杂,有更好的解决方案吗?
答案 0 :(得分:0)
最终的解决方案是在任务中启动主管线程,该管理员线程会从竞争任务中回复“发现”消息。
工作流程就是这样。
除了几个任务同时启动(即在工作人员重启之后)外,此方法工作正常。为避免这种需要使订阅过程具有原子性,请使用Redis锁定:
class RedisChannel:
def __init__(self, channel_id):
self.channel_id = channel_id
self.redis = StrictRedis()
self.channel = self.redis.pubsub()
with self.redis.lock(channel_id):
self.channel.subscribe(channel_id)