Python 如何在运行另一个任务之前检测做类似工作的芹菜任务?

Python 如何在运行另一个任务之前检测做类似工作的芹菜任务?,python,celery,ipc,Python,Celery,Ipc,我的芹菜任务是对某个数据库存储的实体进行耗时的计算。工作流是这样的:从数据库中获取信息,将其编译成可序列化的对象,保存对象。其他任务是对加载的对象执行其他计算(如渲染图像) 但序列化非常耗时,所以我希望每个实体运行一个任务一段时间,将序列化对象保存在内存中,并处理通过消息队列(redis pubsub)传递的客户端请求。如果一段时间内没有请求,任务将退出。在此之后,若客户机需要完成一些工作,它将运行另一个任务,该任务将加载对象,对其进行处理,并对其他工作进行一段时间的调整。此任务应在启动时进行检

我的芹菜任务是对某个数据库存储的实体进行耗时的计算。工作流是这样的:从数据库中获取信息,将其编译成可序列化的对象,保存对象。其他任务是对加载的对象执行其他计算(如渲染图像)

但序列化非常耗时,所以我希望每个实体运行一个任务一段时间,将序列化对象保存在内存中,并处理通过消息队列(redis pubsub)传递的客户端请求。如果一段时间内没有请求,任务将退出。在此之后,若客户机需要完成一些工作,它将运行另一个任务,该任务将加载对象,对其进行处理,并对其他工作进行一段时间的调整。此任务应在启动时进行检查,以避免冲突,前提是此特定实体上只有一个工作进程那么,检查此实体是否正在运行其他任务的最佳策略是什么?

1) 第一个想法是将消息发送到和实体关联的某个通道,并等待响应。坏主意,目标任务可能忙于计算,而等待超时响应只是浪费时间

2) 在数据库中存储芹菜任务id更糟糕——任务可以被终止,但记录将保留,所以我们需要确保目标任务是活动的

3) 第三个想法是检查工人是否在运行任务,检查实体id的状态(任务将在启动时提供)。似乎也会发生一些冲突,例如,如果计划了多个任务,但尚未运行


现在,我认为idea 1在这样的修改下是最好的:任务将在启动时将消息发送到实体通道,并使用它的启动时间,但随后立即开始工作,而不是等待响应。然后,它检查消息队列,如果有人响应,他们会比较时间戳和时间戳较大的任务退出。似乎已经够复杂了,有更好的解决方案吗?

最终的解决方案是在任务中启动主管线程,该线程响应来自竞争任务的“发现”消息

所以工作流就是这样

  • 任务启动,然后使用实体ID订阅Redis PubSub通道
  • 任务向通道发送“发现”消息
  • 任务等待一点
  • 在通道中的传入消息中搜索“回复”任务,如果找到,则退出
  • 任务启动主管线程,该线程通过“回复”对所有传入的“发现”消息进行回复
  • 除了几个任务同时启动(即在工作人员重新启动后)外,这一切正常。要避免这种需要,请使用Redis lock使subscription进程原子化:

    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)