flask 通常使用 flask_apscheduler 框架设计定时任务,flask_apscheduler 功能很全面,能按设定的时间规则执行任务,可以持久化到各类数据库(mysql,redis,mongodb),实现对定时任务增、删、改、查等操作。
安装
pip3 install flask_apscheduler
1、调用方法
方法一:使用 Config 类配置时间规则
from flask import Flask
from flask_apscheduler import APScheduler
class Config(object):
# 列表类型,如有需要可以定义多个job
JOBS = [
{
'id': 'job_1', # 一个标识
'func': '__main__:job1', # 指定运行的函数
'args': (1, 2), # 传入函数的参数
'trigger': 'interval', # 指定 定时任务的类型
'seconds': 5 # 运行的间隔时间
}
]
SCHEDULER_API_ENABLED = True
def job1(a, b): # 运行的定时任务的函数
print(str(a) + ' ' + str(b))
if __name__ == '__main__':
app = Flask(__name__) # 实例化flask
app.config.from_object(Config()) # 为实例化的 flask 引入配置
scheduler = APScheduler() # 实例化 APScheduler
scheduler.init_app(app) # 把任务列表放入 flask
scheduler.start() # 启动任务列表
app.debug = True
app.run(host='0.0.0.0',port=8000) # 启动 flask
方法二:使用装饰器
from flask import Flask
from flask_apscheduler import APScheduler
# 实例化 APScheduler
scheduler = APScheduler()
@scheduler.task('interval', id='job_1', args=(1,2),seconds=5)
def job1(a, b): # 运行的定时任务的函数
print(str(a) + ' ' + str(b))
if __name__ == '__main__':
app = Flask(__name__) # 实例化flask
scheduler.start() # 启动任务列表
app.debug=True
app.run(host='0.0.0.0',port= 8000) # 启动 flask
方法三:通过调用 flask_apscheduler 的 api (推荐)
from flask import Flask
from apscheduler.schedulers.background import BackgroundScheduler
# 调度器在后台线程中运行,不会阻塞当前线程
scheduler = BackgroundScheduler()
def job1(a, b): # 运行的定时任务的函数
print(str(a) + ' ' + str(b))
scheduler.add_job(func=job1, args=("1","2"),id="job_1", trigger="interval", seconds=5, replace_existing=False)
'''
func:定时任务执行的函数名称。
args:任务执行函数的位置参数,若无参数可不填
id:任务id,唯一标识,修改,删除均以任务id作为标识
trigger:触发器类型,参数可选:date、interval、cron
replace_existing:将任务持久化至数据库中时,此参数必须添加,值为True。并且id值必须有。不然当程序重新启动时,任务会被重复添加。
'''
if __name__ == '__main__':
app = Flask(__name__) # 实例化flask
scheduler.start() # 启动任务列表
app.debug=True
app.run(host='0.0.0.0',port= 8000) # 启动 flask
实例对象 scheduler 拥有增、删、改、查等基本用法:
新增任务:add_job()
编辑任务:modify_job()
删除任务:remove_job(id)(删除所有任务:remove_all_jobs())
查询任务:get_job(id)(查询所有任务:get_jobs())
暂停任务:pause_job(id)
恢复任务:resume_job(id)
运行任务:run_job(id)(立即运行,无视任务设置的时间规则)
2、四个基础模块:
2.1 任务调度器
Apscheduler提供的调度器有7种:
BlockingScheduler : 调度器在当前进程的主线程中运行,会阻塞当前线程。
BackgroundScheduler : 调度器在后台线程中运行,不会阻塞当前线程。
AsyncIOScheduler : 结合 asyncio 模块(一个异步框架)一起使用。
GeventScheduler : 程序中使用 gevent(高性能的Python并发框架)作为IO模型,和 GeventExecutor 配合使用。
TornadoScheduler : 程序中使用 Tornado(一个web框架)的IO模型,用 ioloop.add_timeout 完成定时唤醒。
TwistedScheduler : 配合 TwistedExecutor,用 reactor.callLater 完成定时唤醒。
QtScheduler : Qt 应用,需使用QTimer完成定时唤醒。
from apscheduler.schedulers.background import BackgroundScheduler,BlockingScheduler
# 调度器在后台线程中运行,不会阻塞当前线程
scheduler = BackgroundScheduler()
# 调度器在当前进程的主线程中运行,会阻塞当前线程
# scheduler = BlockingScheduler()
2.2 执行器
用于设置线程池、进程池、协程池等,Apscheduler提供的执行器有6种:
ThreadPoolExecutor: 线程池执行器。
ProcessPoolExecutor: 进程池执行器。
GeventExecutor: Gevent程序执行器。
TornadoExecutor: Tornado程序执行器。
TwistedExecutor: Twisted程序执行器。
AsyncIOExecutor: asyncio程序执行器。
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.executors.pool import ThreadPoolExecutor,ProcessPoolExecutor
# 配置线程池,支持最多5个线程同时执行
executors = {'default': ThreadPoolExecutor(5)}
# 配置进程池,支持最多5个进程同时执行
# executors = {'default': ProcessPoolExecutor(5)}
#创建类,导入配置
scheduler = BackgroundScheduler(executors=executors)
2.2.1 任务配置
# 任务相关配置
defaults = {
# 不合并执行
'coalesce': False,
# 同一时间同个任务最大执行次数为3
'max_instances': 3,
# 任务错过当前时间60s内,仍然可以触发任务
'misfire_grace_time':60
}
# 创建类,导入配置
scheduler = BackgroundScheduler(job_defaults=defaults)
2.3 任务存储器
任务默认是存储在内存里的,服务重启后,内存里的任务会丢失。将任务保存在数据库中,每次启动会读取数据库的信息,可以避免服务重启丢失信息的问题。
from flask import Flask
from apscheduler.schedulers.background import BackgroundScheduler
# 数据持久化至Mysql,默认table名为apscheduler_jobs
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
jobstores = {'default': SQLAlchemyJobStore(url="mysql+pymysql://root:123456@127.0.0.1:3306/work")}
# 数据持久化至MongoDB
# from apscheduler.jobstores.mongodb import MongoDBJobStore
# jobstores = {'default': MongoDBJobStore(host="127.0.0.1",port=27017, database="TEST", collection="jobs")}
# 数据持久化至redis
# from apscheduler.jobstores.redis import RedisJobStore
# jobstores = {'default': RedisJobStore(host="127.0.0.1",port=6379, db=0)}
# 引入配置的方法,在创建类时加入配置项
scheduler = BackgroundScheduler(jobstores=jobstores)
def job1(a, b): # 运行的定时任务的函数
print(str(a) + ' ' + str(b))
scheduler.add_job(func=job1, args=("1", "2"), id="job_1", trigger="interval", seconds=5, replace_existing=True)
if __name__ == '__main__':
app = Flask(__name__) # 实例化flask
scheduler.start() # 启动任务列表
app.debug = True
app.run(host='0.0.0.0', port=8000) # 启动 flask
数据库字段:
2.4 触发器类型
当你开始定时任务时,需要为定时策略选择一个触发器(设置 class Config 中 trigger 的值)。flask_apscheduler 提供了三种类型的触发器。
- date 一次性指定固定时间,只执行一次
- interval 间隔调度,隔多长时间执行一次
- cron 指定相对时间执行,比如:每月1号、每星期一执行
2.4.1 date 最基本的一种调度,指定固定时间,只执行一次
- run_date(str)– 精确时间
class Config(object):
JOBS = [
{
'id': 'job1',
'func': '__main__:job1',
'args': (1, 2),
'trigger': 'date', # 指定任务触发器 date
'run_date': '2020-7-23 16:50:00' # 指定时间 2020-7-23 16:50:00 执行
}
]
SCHEDULER_API_ENABLED = True
2.4.2 interval 通过设置 时间间隔 来运行定时任务
- weeks (int) – 间隔几周
- days (int) – 间隔几天
- hours (int) – 间隔几小时
- minutes (int) – 间隔几分钟
- seconds (int) – 间隔多少秒
- start_date (datetime|str) – 开始日期
- end_date (datetime|str) – 结束日期
class Config(object):
JOBS = [
{
'id': 'job1',
'func': '__main__:job1',
'args': (1, 2),
'trigger': 'interval', # 指定任务触发器 interval
'hours': 5 # 每间隔5h执行
}
]
SCHEDULER_API_ENABLED = True
2.4.3 cron 通过设置 相对时间 来运行定时任务
- year (int|str) – 年,4位数字
- month (int|str) – 月 (范围1-12)
- day (int|str) – 日 (范围1-31)
- week (int|str) – 周 (范围1-53)
- day_of_week (int|str) – 周内第几天或者星期几 (范围0-6 或者 mon,tue,wed,thu,fri,sat,sun)
- hour (int|str) – 时 (范围0-23)
- minute (int|str) – 分 (范围0-59)
- second (int|str) – 秒 (范围0-59)
- start_date (datetime|str) – 最早开始日期(包含)
- end_date (datetime|str) – 最晚结束时间(包含)
class Config(object):
JOBS = [
{
'id': 'job1',
'func': '__main__:job1',
'args': (1, 2),
'trigger': 'cron', # 指定任务触发器 cron
'day_of_week': 'mon-fri', # 每周1至周5早上6点执行
'hour': 6,
'minute': 00
}
]
SCHEDULER_API_ENABLED = True
设置时区
开发好定时脚本后部署到 K8S,发现报错 Timezone offset does not match system offset: 0 != 28800. Please, check your config files.
本地运行好好的,为什么服务器上就报错了呢?
原因是系统的时区和代码运行的时区不一致导致的。解决方法是在初始化 APScheduler() 的时候加上时区:BackgroundScheduler(timezone="Asia/Shanghai")
'''...'''
from apscheduler.schedulers.background import BackgroundScheduler
class config:
JOBS = ['''...''']
SCHEDULER_TIMEZONE = 'Asia/Shanghai'
'''...'''
if __name__ == '__main__':
scheduler = APScheduler(BackgroundScheduler(timezone="Asia/Shanghai"))
scheduler.init_app(app)
scheduler.start()
app.run()