背景
使用Celery执行定时任务时,若在启动celery beat的时候没有指定-s参数,则会在celery_app同级目录下生成celerybeat-schedule.db文件,用于存放定时任务上一次的执行信息。
接下来着重分析celerybeat-schedule.db,给celery定时任务相关问题提供一个排查思路。
Berkeley DB
Berkeley DB是一个开源的文件数据库,可以保存任何类型的键/值对,访问速度快,可以支持数千的并发线程同时操作数据库,支持最大256TB的数据。
celerybeat-schedule.db就是采用的Berkeley DB
需要的工具
- db5.3-util 命令行工具,可以在命令行查询Berkeley DB的基本信息,比如版本信息等。主要用到的命令db5.3_dump.
db5.3_dump celerybeat-schedule.db
VERSION=3
format=bytevalue
type=hash
h_nelem=5
db_pagesize=4096
HEADER=END
....
8003580d000000417369612f5368616e6768616971002e
7574635f656e61626c6564
8003882e
DATA=END
可以看到Berkeley DB版本是3,数值类型是byte类型,存放的type类型是hash值,h_nelem表示有5个hash值。使用db5.3工具只能看到一些属性信息,是无法查看到内部结构数据的。
- shelve python模块,通过api的方式访问Berkeley DB数据库信息。
celerybeat-schedule.db详细分析
import shelve
s = shelve.open('celerybeat-schedule') #注意不能加后缀.db否则会报错
try:
for key in s.keys():
print(key, s.get(key))
finally:
s.close()
这段简短的代码,可以打印出目前所存储到的信息,实际输出如下:
__version__ 3.1.25
entries {'push_data': <Entry: push_data agent.celery_app.cluster_task.push_task() <crontab: 59 23 * * * (m/h/d/dM/MY)>}
tz Asia/Shanghai
utc_enabled True
可以看到有4项信息,分别是version 、entries、tz、utc_enabled。
version: 版本信息3.1.25。
entries:存放上一次任务执行信息,包括执行函数,运行参数,执行时间等。
tz:表示时区,这个参数信息很重要,若是与服务器时区对不上,则有可能导致任务不会执行。
utc_enabled:是否使用utc时间。
et = entries['push_data']
help(et)
class ScheduleEntry(builtins.object)
An entry in the scheduler.
:keyword name: see :attr:`name`.
:keyword schedule: see :attr:`schedule`.
:keyword args: see :attr:`args`.
:keyword kwargs: see :attr:`kwargs`.
:keyword options: see :attr:`options`.
:keyword last_run_at: see :attr:`last_run_at`.
:keyword total_run_count: see :attr:`total_run_count`.
:keyword relative: Is the time relative to when the server starts?
可以看到Entry是class ScheduleEntry类的一个实例,并且ScheduleEntry带有一些属性参数,接下来我们输出对应的属性,由于是对象实例,所以需要使用下标的方式访问。
et.name : 'push_data'
et.schedule: <crontab: 59 23 * * * (m/h/d/dM/MY)>
et.args: {}
et.kwargs: {}
et.options: {}
et.last_run_at: datetime.datetime(2020, 3, 20, 9, 9, 51, 728611)
et.total_run_count: 150
参数说明:
1. et.name :任务执行名称,实例中为'push_data'
2. et.schedule:任务调度器,实例中表示每天23:59分执行一次任务。
3. et.args:任务参数,实例中为空
4. et.kwargs:任务参数,实例中为空
5. et.options:任务选择参数,实例中为空
6. et.last_run_at:实例上一次执行时间
7. et.total_run_count:截止当前总共执行的次数
-
其中比较重要的参数是et.schedule、et.last_run_at,celery beat每次执行周期时间到的时候,会根据任务上一次的执行时间来判断当前任务是否需要执行。这对服务器时间要求就比较严格,发现任务不执行时可以排查以下几个方面:
- 如果存在celerybeat-schedule文件,那么读取后根据上一次执行的时间,继续执行。
- 如果不存在celerybeat-schedule文件,那么会立即执行一次。
- 如果存在celerybeat-schedule文件,读取后,发现间隔时间已过,那么会立即执行。
- 如果存在celerybeat-schedule文件,读取后,发现et.last_run_at超前于系统时间,则celery会认为时间未到,那么不会执行任务。
出现时间问题如何恢复
- 若出现像上文中提到的时间问题,首先按照以上思路进行排查,服务时区是否对应,时间是否正常等,最简单的方法就是删除celerybeat-schedule文件,并重新启动celery beat服务即可。
- 启动celery beat服务时,可以使用-s参数将celerybeat-schedule重定向到/var/run临时目录,无论系统宕机还是正常关机,celerybeat-schedule会重新生成,不影响任务执行。
总结
以上只是提供了一个排查celery beat任务不执行的思路,主要是学习的目的。解决问题的方法比较简单,重点是真实掌握了整个问题的来龙去脉。
作者:ScarecrowLAN
链接:https://www.jianshu.com/p/51644ab92639
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69999831/viewspace-3156704/
,如需转载,请注明出处,否则将追究法律责任。