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、四个基础模块:

celery flask python 定时任务 flask 定时任务方案_实例化

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

数据库字段:

celery flask python 定时任务 flask 定时任务方案_实例化_02

 

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. 

celery flask python 定时任务 flask 定时任务方案_flask_apscheduler_03

 

本地运行好好的,为什么服务器上就报错了呢?

原因是系统的时区和代码运行的时区不一致导致的。解决方法是在初始化 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()