一、介绍:

APScheduler的全称是Advanced Python Scheduler。它是一个轻量级的 Python 定时任务调度框架。

APScheduler 支持三种调度任务:固定时间间隔,固定时间点(日期),它还支持异步执行、后台执行调度任务。

这里只介绍如何执行调度任务

二、安装:

pip install apscheduler

三、基本概念
1. APScheduler四大组件:
触发器 triggers :用于设定触发任务的条件
任务储存器 job stores:用于存放任务,把任务存放在内存或数据库中
执行器 executors: 用于执行任务,可以设定执行模式为单线程或线程池
调度器 schedulers: 把上方三个组件作为参数,通过创建调度器实例来运行
1.1 触发器 triggers
触发器包含调度逻辑。每个任务都有自己的触发器,用于确定何时应该运行作业。除了初始配置之外,触发器完全是无状态的。

1.2 任务储存器 job stores
默认情况下,任务存放在内存中。也可以配置存放在不同类型的数据库中。如果任务存放在数据库中,那么任务的存取有一个序列化和反序列化的过程,同时修改和搜索任务的功能也是由任务储存器实现。
注意一个任务储存器不要共享给多个调度器,否则会导致状态混乱

1.3 执行器 executors
任务会被执行器放入线程池或进程池去执行,执行完毕后,执行器会通知调度器。

1.4 调度器 schedulers
一个调度器由上方三个组件构成,一般来说,一个程序只要有一个调度器就可以了。开发者也不必直接操作任务储存器、执行器以及触发器,因为调度器提供了统一的接口,通过调度器就可以操作组件,比如任务的增删改查

 

2. APScheduler有三种内置的触发器:
date 日期:触发任务运行的具体日期
interval 间隔:触发任务运行的时间间隔
cron 周期:触发任务运行的周期
calendarinterval:当您想要在一天中的特定时间以日历为基础的间隔运行任务时使用
一个任务也可以设定多种触发器,比如,可以设定同时满足所有触发器条件而触发,或者满足一项即触发。

2.1 date 是最基本的一种调度,作业任务只会执行一次。它表示特定的时间点触发。它的参数如下:
参数 说明
run_date(datetime or str) 任务运行的日期或者时间
timezone(datetime.tzinfo or str) 指定时区

代码:
from apscheduler.schedulers.blocking import BlockingScheduler
#创建执行的scheduler
scheduler = BlockingScheduler()
def works():
print(1111)
scheduler.add_job(works,'data',run_date=datetime.datetime(2020,12,4,15,54,0))#定时运行,只运行一次
scheduler.start()#启动scheduler


2.2 interval 周期触发任务
固定时间间隔触发。interval 间隔调度,参数如下:
参数 说明
weeks(int) 间隔几周
days(int) 间隔几天
hours(int) 间隔几小时
minutes(int) 间隔几分钟
seconds(int) 间隔多少秒
start_date(datetime or str) 开始日期
end_date(datetime or str) 结束日期
timezone(datetime.tzinfo or str) 时区

代码:
from apscheduler.schedulers.blocking import BlockingScheduler
#创建执行的scheduler
scheduler = BlockingScheduler()
def works():
print(1111)
#interval触发器,固定时间间隔触发,每两秒运行一次
scheduler.add_job(works, 'interval', seconds=2)
scheduler.start()#启动scheduler


2.3 cron 触发器
在特定时间周期性地触发,和Linux crontab格式兼容。它是功能最强大的触发器。
cron 参数:
参数 说明
year(int or str) 年,4位数字
month(int or str) 月(范围1-12)
day(int or str) 日(范围1-31)
week(int or str) 周(范围1-53)
day_of_week(int or str) 周内第几天或者星期几(范围0-6或者mon,tue,wed,thu,fri,stat,sun)
hour(int or str) 时(0-23)
minute(int or str) 分(0-59)
second(int or str) 秒(0-59)
start_date(datetime or str) 最早开始日期(含)
end_date(datetime or str) 最晚结束日期(含)
timezone(datetime.tzinfo or str) 指定时区

代码:
from apscheduler.schedulers.blocking import BlockingScheduler
#创建后台执行的scheduler
scheduler = BlockingScheduler()
def works():
print(1111)
#interval触发器,固定时间间隔触发,每两秒运行一次
scheduler.add_job(works,'cron',day_of_week='1,3,6',hour='6',minute='30')
scheduler.start()#启动scheduler

四.注意事项

1.如果引用的其他脚本函数,需要将函数的包放置在任务函数包下

2.任务设置为interval或是cron等间隔时,第一次是不会执行的

3.如果使用的是BackgroundScheduler任务,那如果要执行子任务,那么主任务不能退出执行,

4.如果你是想在特定的小时(hour)执行任务,一定要设定好timezone参数,不然会有时差,会导致不会在特定的任务执行

查询本地时区

from tzlocal import get_localzone
tz = get_localzone()
print(tz)

  

五.个人配置

"""
管理全部的定时任务
使用框架:APScheduler
"""
import time
import gc
import json
import requests
from datetime import datetime
import pandas as pd
from sqlalchemy.dialects.mysql import MEDIUMINT,VARCHAR,DATETIME


from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.schedulers.blocking import BlockingScheduler
# from apscheduler.jobstores.mongodb import MongoDBJobStore
from apscheduler.jobstores.redis import RedisJobStore
from apscheduler.jobstores.memory import MemoryJobStore
from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor
# 时间监听器
from apscheduler.events import EVENT_JOB_EXECUTED, EVENT_JOB_ERROR
import logging

from java_interface import query_nickname, account_id_index
from my_toolkit import chinese_check,sql_write_read,public_function



LOGGNAME = 'scheduler.txt'

logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S',
                    filename=LOGGNAME,
                    filemode='a')

REDIS = {
    'host': '127.0.0.1',
    'port': '6379',
    'db': 4,
    'password': '',

}


def scheduler_listener(event):
    """事件监听器"""
    if event.exception:
        print(f'{event.job_id}:任务出错了!!!')
    else:
        print(f'{event.job_id}:任务照常运行,完成...')



if __name__ == '__main__':
    # 触发器配置项:作业存储后台设置,执行器执行方式,调度器
    jobstores = {
        'redis': RedisJobStore(jobs_key='dispatched_jobs', run_times_key='dispatched_running',**REDIS),
        # 'default':MemoryJobStore()
    }
    executors = {
        'default': ThreadPoolExecutor(10),
        'processpool': ProcessPoolExecutor(5)
    }
    job_defaults = {
        'coalesce': False,
        'max_instances': 5
    }

    scheduler = BackgroundScheduler(timezone='Asia/Shanghai', jobstores=jobstores, executors=executors, job_defaults=job_defaults)
    # 添加任务
    scheduler.add_job(query_nickname.request_nickname, trigger='cron', jobstore='redis',id='query_nickname', hour='10', replace_existing=True)
    scheduler.add_job(account_id_index.station_id_index_from_api, trigger='cron',jobstore='redis', id='query_account_id_index', hour='10',replace_existing=True)

    # 添加事件监听器
    scheduler.add_listener(scheduler_listener, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)
    # 添加日志
    scheduler._logger = logging
    # 开始进程
    scheduler.start()

    while 1:
        time.sleep(1000)

 六、调度流程