APScheduler 学习笔记

APScheduler 学习笔记

1. 简介

pass

2. 安装

2.1 使用pip安装

pip install apscheduler

2.2 下载后执行python
下载地址:APScheduler · PyPI

python setup.py install

3 基本概念

APScheduler 有四种组件分别为

  1. triggers
  2. job stores
  3. executors
  4. schedulers
eg:
from apscheduler.schedulers.blocking import BlockingScheduler
import time

# 实例化一个调度器
scheduler = BlockingScheduler()

def job1():
    print "%s: 执行任务"  % time.asctime()

# 添加任务并设置触发方式为3s一次
scheduler.add_job(job1, 'interval', seconds=3)

# 开始运行调度器
scheduler.start()

4 schedulers任务调度组件

调度器 说明
BlockingScheduler 调度器是应用中唯一要运行的东西时。
BackgroundScheduler 当没有运行任何其他框架,并希望调度器在应用的后台执行时使用。
AsyncIOScheduler 程序使用了asyncio(一个异步框架)时使用。
GeventScheduler 程序使用了gevent(高性能的Python并发框架)时使用。
TornadoScheduler 程序基于Tornado(一个web框架)时使用。
TwistedScheduler 程序基于Tornado(一个web框架)的时候使用。
QtScheduler 应用是一个Qt应用的时候可以使用

4.1 BlockingScheduler

from apscheduler.schedulers.blocking import BlockingScheduler
import time

scheduler = BlockingScheduler()

def job_test():
    print "%s: 执行任务"  % time.asctime()

scheduler.add_job(job_test, 'interval', seconds=3)
scheduler.start()

4.2 BackgroundScheduler

from apscheduler.schedulers.background import BackgroundScheduler
import time

scheduler = BackgroundScheduler()

def job_test():
    print "%s: 执行任务"  % time.asctime()

scheduler.add_job(job_test, 'interval', seconds=3)
scheduler.start()

4.3 AsynclOScheduler

from apscheduler.schedulers.asyncio import AsyncIOScheduler
try:
    import asyncio
except ImportError:
    import trollius as asyncio
...
...
# while True:pass 
try:
    asyncio.get_event_loop().run_forever()
except (KeyboardInterrupt, SystemExit):
    pass

4.4 GeventScheduler

from apscheduler.schedulers.gevent import GeventScheduler

...
...

g = scheduler.start()
# while True:pass
try:
    g.join()
except (KeyboardInterrupt, SystemExit):
    pass

4.5 TornadoScheduler

from tornado.ioloop import IOLoop
from apscheduler.schedulers.tornado import TornadoScheduler

...
...

# while True:pass
try:
    IOLoop.instance().start()
except (KeyboardInterrupt, SystemExit):
    pass

4.6 TwistedScheduler:Twisted

from twisted.internet import reactor
from apscheduler.schedulers.twisted import TwistedScheduler

...
...

# while True:pass
try:
    reactor.run()
except (KeyboardInterrupt, SystemExit):
    pass

4.7 调度器操作

开启 scheduler.start()
关闭 scheduler.shutdown()
暂停 scheduler.pause()
继续 scheduler.resume()

5. triggers任务触发器组件

当调度作业的时,需要为这个作业选择一个触发器,用来描述这个作业何时被触,任务触发器组件,提供有三种内置的任务触发方式:

触发方式类型 说明
date 在某个时间点只运行一次作业时使用
interval 按固定的时间间隔运行作业时使用
cron 类linux下的crontab格式,属于定时调度

5.1 一次性调度data

参数 格式 说明
run_date datetime/str 在某个时间点只运行一次作业时使用
timezone datetime.tzinfo/str 指定时区
eg:
# 2016-12-12运行一次job_function
sched.add_job(job_function, 'date', run_date=date(2016, 12, 12), args=['text'])

# 2016-12-12 12:00:00运行一次job_function
sched.add_job(job_function, 'date', run_date=datetime(2016, 12, 12, 12, 0, 0), args=['text'])

5.2 间隔调度interval

参数 格式 说明
year int/str
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 最晚结束时间(包含指定时间)
timezone datetime.tzinfo/str 指定时区

eg:


5.3 定时调度cron

参数 格式 说明
year int/str
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 最晚结束时间(包含指定时间)
timezone datetime.tzinfo/str 指定时区
eg:
# job_function将会在6,7,8,11,12月的第3个周五的1,2,3点运行
sched.add_job(job_function, 'cron', month='6-8,11-12', day='3rd fri', hour='0-3')

# 截止到2016-12-30 00:00:00,每周一到周五早上五点半运行job_function
sched.add_job(job_function, 'cron', day_of_week='mon-fri', hour=5, minute=30, end_date='2016-12-31')

6.job_stores 任务保存组件

提供任务保存方式

6.1. base

6.2. memory

6.3. mongodb

scheduler.add_jobstore('mongodb', collection='example_jobs')

6.4. redis

scheduler.add_jobstore('redis', jobs_key='example.jobs', run_times_key='example.run_times')

6.6. rethinkdb

scheduler.add_jobstore('rethinkdb', database='apscheduler_example')

6.7. sqlalchemy

scheduler.add_jobstore('sqlalchemy', url=url)

6.7. zookeeper

scheduler.add_jobstore('zookeeper', path='/example_jobs')
Django中使用示例:
scheduler.add_jobstore(DjangoJobStore(), "default")

7. executors 任务调度组件

7.1 base

pass

7.2 debug

pass

7.3 gevent

pass

7.4 pool(max_workers=10)

pass

7.5 twisted

pass

8. 任务操作

8.1 add_job添加任务

如果使用了任务的存储,开启时最好添加replace_existing=True,否则每次开启都会创建任务的副本
开启后任务不会马上启动,可修改trigger参数

8.2 remove_job删除任务

# 根据任务实例删除
job = scheduler.add_job(myfunc, 'interval', minutes=2)
job.remove()

# 根据任务id删除
scheduler.add_job(myfunc, 'interval', minutes=2, id='my_job_id')
scheduler.remove_job('my_job_id')

8.3 pause_job暂停任务

8.4 resume_job继续任务

job = scheduler.add_job(myfunc, 'interval', minutes=2)
# 根据任务实例
job.pause()
job.resume()

# 根据任务id暂停
scheduler.add_job(myfunc, 'interval', minutes=2, id='my_job_id')
scheduler.pause_job('my_job_id')
scheduler.resume_job('my_job_id')

8.5 modify 任务修饰

job.modify(max_instances=6, name='Alternate name')

8.6 reschedule_job重设任务

scheduler.reschedule_job('my_job_id', trigger='cron', minute='*/5')

调度示例(摘录于https://zhuanlan.zhihu.com/p/95563033)


import asyncio
import datetime

from apscheduler.events import EVENT_JOB_EXECUTED
from apscheduler.executors.asyncio import AsyncIOExecutor
from apscheduler.jobstores.redis import RedisJobStore  # 需要安装redis
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.interval import IntervalTrigger
from apscheduler.triggers.cron import CronTrigger

# 定义jobstore  使用redis 存储job信息
default_redis_jobstore = RedisJobStore(
    db=2,
    jobs_key="apschedulers.default_jobs",
    run_times_key="apschedulers.default_run_times",
    host="127.0.0.1",
    port=6379,
    password="test"
)

# 定义executor 使用asyncio是的调度执行规则
first_executor = AsyncIOExecutor()

# 初始化scheduler时,可以直接指定jobstore和executor
init_scheduler_options = {
    "jobstores": {
        # first 为 jobstore的名字,在创建Job时直接直接此名字即可
        "default": default_redis_jobstore
    },
    "executors": {
        # first 为 executor 的名字,在创建Job时直接直接此名字,执行时则会使用此executor执行
        "first": first_executor
    },
    # 创建job时的默认参数
    "job_defaults": {
        'coalesce': False,  # 是否合并执行
        'max_instances': 1  # 最大实例数
    }
}
# 创建scheduler
scheduler = AsyncIOScheduler(**init_scheduler_options)

# 启动调度
scheduler.start()

second_redis_jobstore = RedisJobStore(
    db=2,
    jobs_key="apschedulers.second_jobs",
    run_times_key="apschedulers.second_run_times",
    host="127.0.0.1",
    port=6379,
    password="test"
)

scheduler.add_jobstore(second_redis_jobstore, 'second')
# 定义executor 使用asyncio是的调度执行规则
second_executor = AsyncIOExecutor()
scheduler.add_executor(second_executor, "second")


# ***********               关于 APScheduler中有关Event相关使用示例               *************
# 定义函数监听事件
def job_execute(event):
    """
    监听事件处理
    :param event:
    :return:
    """
    print(
        "job执行job:\ncode => {}\njob.id => {}\njobstore=>{}".format(
            event.code,
            event.job_id,
            event.jobstore
        ))


# 给EVENT_JOB_EXECUTED[执行完成job事件]添加回调,这里就是每次Job执行完成了我们就输出一些信息
scheduler.add_listener(job_execute, EVENT_JOB_EXECUTED)


# ***********               关于 APScheduler中有关Job使用示例               *************
# 使用的是asyncio,所以job执行的函数可以是一个协程,也可以是一个普通函数,AsyncIOExecutor会根据配置的函数来进行调度,
# 如果是协程则会直接丢入到loop中,如果是普通函数则会启用线程处理
# 我们定义两个函数来看看执行的结果

def interval_func(message):
    print("现在时间: {}".format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
    print("我是普通函数")
    print(message)


async def async_func(message):
    print("现在时间: {}".format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
    print("我是协程")
    print(message)


# 将上述的两个函数按照不同的方式创造触发器来执行
# ***********               关于 APScheduler中有关Trigger使用示例               *************
# 使用Trigger有两种方式,一种是用类创建使用,另一个是使用字符串的方式
# 使用字符串指定别名, scheduler初始化时已将其定义的trigger加载,所以指定字符串可以直接使用


if scheduler.get_job("interval_func_test", "default"):
    # 存在的话,先删除
    scheduler.remove_job("interval_func_test", "default")

# 立马开始 2分钟后结束, 每10s执行一次 存储到first jobstore  second执行
scheduler.add_job(interval_func, "interval",
                  args=["我是10s执行一次,存放在jobstore default, executor default"],
                  seconds=10,
                  id="interval_func_test",
                  jobstore="default",
                  executor="default",
                  start_date=datetime.datetime.now(),
                  end_date=datetime.datetime.now() + datetime.timedelta(seconds=240))

# 先创建tigger
trigger = IntervalTrigger(seconds=5)

if scheduler.get_job("interval_func_test_2", "second"):
    # 存在的话,先删除
    scheduler.remove_job("interval_func_test_2", "second")
# 每隔5s执行一次
scheduler.add_job(async_func, trigger, args=["我是每隔5s执行一次,存放在jobstore second, executor = second"],
                  id="interval_func_test_2",
                  jobstore="second",
                  executor="second")

# 使用协程的函数执行,且使用cron的方式配置触发器

if scheduler.get_job("cron_func_test", "default"):
    # 存在的话,先删除
    scheduler.remove_job("cron_func_test", "default")

# 立马开始 每10s执行一次
scheduler.add_job(async_func, "cron",
                  args=["我是 每分钟 30s  时执行一次,存放在jobstore default, executor default"],
                  second='30',
                  id="cron_func_test",
                  jobstore="default",
                  executor="default")

# 先创建tigger
trigger = CronTrigger(second='20,40')

if scheduler.get_job("cron_func_test_2", "second"):
    # 存在的话,先删除
    scheduler.remove_job("cron_func_test_2", "second")
# 每隔5s执行一次
scheduler.add_job(async_func, trigger, args=["我是每分钟 20s  40s时各执行一次,存放在jobstore second, executor = second"],
                  id="cron_func_test_2",
                  jobstore="second",
                  executor="second")

# 使用创建trigger对象直接创建
print("启动: {}".format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
asyncio.get_event_loop().run_forever()

输出结果部分截取

启动之后,每隔5s运行一次的JOB

启动: 2019-12-05 14:13:11
【这部分是定义的协程函数输出的内容】
现在时间: 2019-12-05 14:13:16
我是协程
我是每隔5s执行一次,存放在jobstore second, executor = second
【这部分是监听job执行完成之后的回调输出】
job执行job: code => 4096
job.id => interval_func_test_2
jobstore=>second

在20s和40s时各执行一次的Job

现在时间: 2019-12-05 14:13:20
我是协程
我是每分钟 20s 40s时各执行一次,存放在jobstore second, executor = second
job执行
job: code => 4096
job.id => cron_func_test_2
jobstore=>second

每隔10s执行一次的job

现在时间: 2019-12-05 14:13:21
我是普通函数
我是10s执行一次,存放在jobstore default, executor default
现在时间: 2019-12-05 14:13:21
我是协程
我是每隔5s执行一次,存放在jobstore second, executor = second
job执行job: code => 4096
job.id => interval_func_test
jobstore=>default
job执行
job: code => 4096
job.id => interval_func_test_2
jobstore=>second

每隔5s执行一次的Job

现在时间: 2019-12-05 14:13:26
我是协程
我是每隔5s执行一次,存放在jobstore second, executor = second
job执行
job: code => 4096
job.id => interval_func_test_2
jobstore=>second

每分钟30s时执行一次

现在时间: 2019-12-05 14:13:30
我是协程
我是 每分钟 30s 时执行一次,存放在jobstore default, executor default
job执行
job: code => 4096
job.id => cron_func_test
jobstore=>default
posted @ 2021-06-29 17:34  路口有雾  阅读(284)  评论(0编辑  收藏  举报