Celery时区设置问题源码探究

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Celery时区设置问题源码探究相关的知识,希望对你有一定的参考价值。

参考技术A

项目中有使用到Celery框架,主要使用Celery来在使用Django搭建的项目中创建延时任务及周期任务。在使用过程中出现过延时任务及周期任务到预定时间未能执行的情况。Google、百度了一些网友的分析及解决方案,大多认为是Celery时区设置导致的问题。然而这些解答大多类似,而且并不能解决我心中的疑惑,因此决定研究源码一探究竟。

这里网上大多数解答存在问题的地方,将延时任务及周期任务混为一谈了。周期任务是存在一个周期,定时执行的任务,类似Linux系统的Crontab定时任务。而延时任务更类似一个普通的异步任务,不同的是存在一个ETA延时时间,这种任务只会执行一次。因此我们会分开讨论两种任务。

celery存在两个时区的配置 enable_utc timezone ,前者表示是否使用UTC时间,后者表示celery使用的时区。celery默认使用UTC时间,若使用默认配置,则celery设置周期任务时,必须使用UTC时间,比如

当系统时间是北京时间时,这样的设置会导致这个任务并不会在每天北京时间9:30执行,而是17:30,因为UTC时间和北京时间相差8小时。因此这里我们将配置修改为

这样周期任务就能正常执行了

大多数网上的解答止步于上述的结果,认为上述设置之后,延时任务就同样没有任何问题了,其实不然,例如

我们准备让这个任务在 2021-08-19 18:10:30 去执行,结果呢

当req.utc为True时,执行to_system_tz方法转换eta,否则直接使用Celery设置的时区转换,这个req.utc又是什么?

从这里可以看出,当我们设置了args参数时,由hybrid_to_proto2返回,继续

omg!!!原来apply_async方法还有一个参数叫utc吗,而且默认值是True,看文档的时候并没有注意到!到这里,我们大概能看出问题的所在了,延时任务也可以认为普通的异步任务,存在自己的时区配置参数,之前提到的enable_utc并不能影响到这里。我们再看看传入的eta做了哪些处理。

传入的native类型的时间,居然直接被转换成UTC时间了!!!

讨论了这么多,我们能得出最终解决Celery时区问题的结论
1、对于周期任务,需要将celery的配置enable_utc设置成False,timezone设置成系统当前的时区
2、对于延时任务,如果需要设置eta,即精确在某一时间执行,则这个eta必须包含时区信息

最终结论相当简单,但是花了大量时间去研究了源码。对于延时任务eta设置曾经也是相当困惑,其实对于官方文档确实有提到,eta必须要包含时区信息,之前并没有注意到

以上是关于Celery时区设置问题源码探究的主要内容,如果未能解决你的问题,请参考以下文章

将celery定时任务设置为根据本地时区触发

celery中时区设置后仍然与后端redis不一致

flower 时区设置

celery 定时任务,使用crontab表达式不执行(版本4.3.x)

在每个时区每天凌晨 3:00 运行 celery 任务?姜戈

高性能分布式任务队列Celery功能探究