https://zhuanlan.zhihu.com/p/95563033
1 概念
名词
job 最小执行单位,创建一个Job,然后指定要执行的函数
trigger 触发器,根据时间规则,计算得到下次执行时间。
executer
next_run_time 触发规则有trigger的时间,或者这个定时执行
func job的执行函数
args job执行函数的参数
kwargs 执行函数的关键字参数
trigger
Trigger有多种种类,指定时间的DateTrigger,指定间隔时间的IntervalTrigger,像Linux的crontab
一样的CronTrigger
Executor
Executor在scheduler中初始化,另外也可通过scheduler的add_executor动态添加Executor。
每个executor都会绑定一个alias,这个作为唯一标识绑定到Job,在实际执行时会根据Job绑定的executor
找到实际的执行器对象,然后根据执行器对象执行Job
Executor的种类会根据不同的调度来选择,如果选择AsyncIO作为调度的库,那么选择AsyncIOExecutor,如果
选择tornado作为调度的库,选择TornadoExecutor,如果选择启动进程作为调度,
选择ThreadPoolExecutor或者ProcessPoolExecutor都可以
Executor的选择需要根据实际的scheduler来选择不同的执行器
Jobstore
Jobstore在scheduler中初始化,另外也可通过scheduler的add_jobstore动态添加Jobstore。每个jobstore
都会绑定一个alias,scheduler在Add Job时,根据指定的jobstore在scheduler中找到相应的jobstore,并
将job添加到jobstore中。
Jobstore主要是通过pickle库的loads和dumps【实现核心是通过python的__getstate__和__setstate__重写
实现】,每次变更时将Job动态保存到存储中,使用时再动态的加载出来,作为存储的可以是redis,也可以
是数据库【通过sqlarchemy这个库集成多种数据库】,也可以是mongodb等
Event
Event是APScheduler在进行某些操作时触发相应的事件,用户可以自定义一些函数来监听这些事件,
当触发某些Event时,做一些具体的操作
常见的比如。Job执行异常事件 EVENT_JOB_ERROR。Job执行时间错过事件 EVENT_JOB_MISSED。
Listener
Listener表示用户自定义监听的一些Event,当Job触发了EVENT_JOB_MISSED事件时
可以根据需求做一些其他处理。
Scheduler
Scheduler是APScheduler的核心,所有相关组件通过其定义。scheduler启动之后,将开始按照配置的任务进行调度。
除了依据所有定义Job的trigger生成的将要调度时间唤醒调度之外。当发生Job信息变更时也会触发调度。
scheduler可根据自身的需求选择不同的组件,如果是使用AsyncIO则选择AsyncIOScheduler,使用tornado则
选择TornadoScheduler。
tornado案例
from datetime import datetime from tornado.ioloop import IOLoop, PeriodicCallback from tornado.web import RequestHandler, Application from apscheduler.schedulers.tornado import TornadoScheduler import json scheduler = TornadoScheduler() def init_scheduler(): global scheduler url = "mysql+pymysql://root:123@192.168.1.2/codo_cron?charset=utf8" scheduler.add_jobstore(jobstore="sqlalchemy", url=url, tablename='api_job') # 持久化存储配置,表会自动创建 scheduler.start() print('[Scheduler Init]APScheduler has been started') # 要执行的定时任务在这里 def task1(): print(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) def task2(): print(datetime.now().strftime('%Y/%m/%d %H:%M:%S')) class SchedulerHandler(RequestHandler): def post(self): data = json.loads(self.request.body.decode("utf-8")) # 判断定时器格式 cron = data.get('cron').strip().split(' ') if len(cron) != 6: return self.write(dict(code=-1, msg='添加失败,格式错误')) cmd = data.get('cmd', None) job_id = data.get('job_id', None) if job_id: try: cron_rel = dict(second=cron[0], minute=cron[1], hour=cron[2], day=cron[3], month=cron[4], day_of_week=cron[5]) scheduler.add_job(func=__name__ + ':' + cmd, # 可调用的函数,(e.g. package.module:some.object) trigger='cron', # 触发器类型,(e.g. ``date``, ``interval`` or ``cron``) # kwargs={'cmd': cmd, 'job_id': job_id}, # 调用函数的关键字参数的字典,函数没有参数就不需要 id=job_id, # job 唯一标识 **cron_rel # 定时任务格式, # (e.g. second=10, minute=*, hour=*, day=*, month=*, day_of_week=*) # 代表每分钟的第10秒执行一次 ) return self.write(dict(code=0, msg='添加成功', job_id=job_id)) except Exception as e: return self.write(dict(code=-1, msg='添加失败: %s' % e)) if __name__ == "__main__": routes = [ (r"/scheduler/?", SchedulerHandler), ] init_scheduler() app = Application(routes, debug=True) app.listen(8888) IOLoop.current().start()