发现问题:
这两天在使用celery的过程中遇到一个问题:
- 我在flask celery中写好任务函数,然后跑flask(任务函数有4个参数)
- 然后跑celery的服务
- 我修改了flask里的celery任务函数(任务函数变成5个参数,且函数体也改了)
- 然后去执行这个任务,发现老是参数个数不对(预期4个,实际给了5个参)。
解决过程:
后来一想celery后端用的是消息队列,如 redis 或 rabbitmq。我们的项目用的redis。redis里的消息队列叫 redis stream,有分组的概念,同一个组里的多个消费者可以不重复的消费队列里的消息,类似 rabbitmq 里的多个worker。
猜测celery的执行任务的过程是这样的:
- 先有一个redis服务在那里跑着
- 启动celery服务,成为某个组里的消费者,启动celery服务时,会加载flask代码里的任务函数
- flask这边也启动服务,作为生产者,当执行任务函数时,实际上是把任务函数的参数序列化为二进制数据,放入redis stream消息队列。
- celery服务从消息队列拿出来的数据,是任务函数的实际参数,然后去执行任务函数。
- 最后celery服务把执行的结果再次返到消息队列(这一步可能有另外一条消息队列,flask作为消费者,celery服务为生产者),让flask任务函数去拿结果,然后把任务函数的二进制结果解析成python需要的类型。
也就是说,只在flask这边更新任务函数,celery服务那边如果不重启,还是旧版本的任务函数。更新flask任务函数,启动flask服务前,需要先重启celery服务。
最后在代码中也验证了这种猜想。由此得出结论:celery里应该有重载任务函数代码的机制。