Python Timer Library: APScheduler

Reference resources:

1 Basic concepts

1.1 Basic Components

1.1.1 Trigger triggers

Conditions used to set trigger tasks

Trigger binds to Job, calculates the trigger time of Job based on the trigger's rules when scheduler schedules to filter Job, and then compares with the current time to determine if this Job will be executed, that is, calculates the next execution time based on the trigger's rules.

There are a variety of Triggers, DateTrigger at a specified time, IntervalTrigger at a specified interval, CronTrigger like crontab on Linux.

When dispatching a job, you need to select a triggers for the job to describe when the job is triggered. APScheduler has three built-in trigger types:

  • "Date": specify the date at one time;
  • How often does "interval" execute at intervals within a time range?
  • The "cron" and "Linux crontab" formats are compatible and most powerful.

1.1.2 Job Storage job stores:

Used to store tasks in memory or in a database

If your application recreates jobs every time it starts, you can use the default job storage (MemoryJobStore), but if you need to keep jobs even when the scheduler restarts or the application runs, you should choose specific job storage based on your application environment.

For example, use Mongo or SQLAlchemy JobStore (to support most RDBMS)

1.1.3 Executor executors

For task execution, you can set the execution mode to single-threaded or thread pool

The choice of an executor depends on which framework you use above, and in most cases, using the default ThreadPoolExecutor already works. If your application involves CPU intensive operations, you might consider using ProcessPoolExecutor to use more CPU cores. You can also use both, using ProcessPoolExecutor as the second executor.

1.1.4 Scheduler schedulers:

Run by creating a dispatcher instance with the above three components as parameters

  • BlockingScheduler: Blocking Scheduler: A program for a run-only scheduler
  • BackgroundScheduler: Background Scheduler: For non-blocking scenarios, the scheduler runs independently in the background
  • AsyncIOScheduler: When your program uses asyncio (an asynchronous framework).
  • GeventScheduler: When your program uses gevent, a high-performance Python concurrency framework.
  • Tornado Scheduler: When your program is based on Tornado, a web framework.
  • TwistedScheduler: When your program uses Twisted (an asynchronous framework)
  • QtScheduler: If your application is a Qt application, you can use it.

The choice of task store depends on whether the task needs to be persisted.
If you are running a task that is stateless, you can handle it by choosing the default task store, MemoryJobStore.
However, if you need to save the state of a task when the program is shut down or restarted, you need to choose a persistent task store.
Author recommendation Use SQLAlchemyJobStore with PostgreSQL as the background database.
This scheme can provide powerful data integration and protection.

2 Simple examples

2.1 Loop Execution Example

2.1.1 Executes every 5s

#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
Explain:
    - Every 5 s Execute once
"""

import datetime
from apscheduler.schedulers.blocking import BlockingScheduler


def job1():
    print("Doing Job", datetime.datetime.now())


scheduler = BlockingScheduler()
scheduler.add_job(job1, "interval", seconds=5, id="job1")
# scheduler.add_job(job1, 'cron', minute="/2", id='job1')	# Execute every minute
# scheduler.add_job(job1, 'interval', hours=1, id='job1')	# Execute every hour
scheduler.start()


>>>
Doing Job 2021-07-20 14:40:19.232279
Doing Job 2021-07-20 14:40:24.239411
Doing Job 2021-07-20 14:40:29.237285
Doing Job 2021-07-20 14:40:34.244373
Doing Job 2021-07-20 14:40:39.237203
Doing Job 2021-07-20 14:40:44.245174
Doing Job 2021-07-20 14:40:49.242486

2.1.2 Execute once per minute for a specified period of time

#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
Explain:
    - 50 per hour-55,Run every minute
"""

import datetime
from apscheduler.schedulers.blocking import BlockingScheduler

scheduler = BlockingScheduler()


@scheduler.scheduled_job("cron", minute="50-55")
def request_update_status():
    print("Doing Job", datetime.datetime.now())


scheduler.start()

2.1.3 Daily scheduled execution

#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
Explain:
    - Run once a day at 1:30 a.m. for 50 seconds
"""

import datetime
from apscheduler.schedulers.blocking import BlockingScheduler

scheduler = BlockingScheduler()

f = open('./task_of_scheduler.txt', 'w', encoding='utf8')


@scheduler.scheduled_job("cron", day_of_week="*", hour="1", minute="30", second="30")
def check_db():
    print("Doing Job, and time:", datetime.datetime.now())


if __name__ == '__main__':
    try:
        scheduler.start()
        f.write("Timed Task Executed Successfully")
    except Exception as e:
        scheduler.shutdown()
        f.write("Timed task execution failed")
    finally:
        f.close()


2.1.4 runs every 2 hours, but only on Saturdays and Sundays

#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
Explain:
    - Run every 2 hours, but only on Saturdays and Sundays
"""

from apscheduler.triggers.combining import AndTrigger
from apscheduler.triggers.interval import IntervalTrigger
from apscheduler.triggers.cron import CronTrigger

trigger = AndTrigger([IntervalTrigger(hours=2),
                      CronTrigger(day_of_week='sat,sun')])
scheduler.add_job(job_function, trigger)

3 Example Details

3.1 triggers Use Details

3.1.1 date triggers a task at a specified point in time

#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
Explain:
    - # Enforced on July 21, 2021
"""

from datetime import date
from apscheduler.schedulers.blocking import BlockingScheduler

scheduler= BlockingScheduler()

def my_job(text):
    print(text)

# Enforced on July 21, 2021
scheduler.add_job(my_job, 'date', run_date=date(2021, 7, 21), args=['text'])

scheduler.start()

3.1.2 datetime type (for exact time)

#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
Explain:
    - # Enforced on July 21, 2021
"""

from datetime import date, datetime
from apscheduler.schedulers.blocking import BlockingScheduler

scheduler= BlockingScheduler()


def my_job(text):
    print(text, datetime.now())


scheduler.add_job(my_job, 'date', run_date=datetime(2021, 7, 20, 14, 56, 00), args=['Doing Job'])
# scheduler.add_job(my_job, 'date', run_date="2021-07-20 14:56:00", args=['Doing Job'])

scheduler.start()

>>>
Doing Job 2021-07-20 14:56:00.013597

3.2 interval cycle trigger task

3.2.1 Triggered every two hours

#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
Explain:
    - Trigger every two hours
"""

from datetime import date, datetime
from apscheduler.schedulers.blocking import BlockingScheduler


def job_function():
    print("Hello World", datetime.now())


schedeler = BlockingScheduler()

# Trigger every 2 hours
schedeler.add_job(job_function, 'interval', hours=2)
schedeler.start()

3.2.2 via scheduled_job() decorator implementation

#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
Explain:
    - adopt scheduled_job()Decorator implementation
"""

import time
from apscheduler.schedulers.blocking import BlockingScheduler

scheduler = BlockingScheduler()


@scheduler.scheduled_job('interval', id='my_job_id', minutes=0.5)
def job_function():
    print("Hello World", time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))


scheduler.start()

>>>
Hello World 2021-07-20 15:06:29
Hello World 2021-07-20 15:06:59

3.3.3 Use start_date and end_date limits the period of time planned to run

#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
Explain:
    - Use start_date and end_date Limit the period of time planned to run
"""

import time
from apscheduler.schedulers.blocking import BlockingScheduler

scheduler = BlockingScheduler()


def job_function():
    print("Hello World: ", time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))


scheduler.add_job(job_function, "interval", minutes=0.5,
                  start_date="2021-07-20 15:10:00", 
                  end_date="2021-07-20 15:15:00")
scheduler.start()

>>>
Hello World:  2021-07-20 15:10:00
Hello World:  2021-07-20 15:10:30
Hello World:  2021-07-20 15:11:00
Hello World:  2021-07-20 15:11:30
Hello World:  2021-07-20 15:12:00
Hello World:  2021-07-20 15:12:30
Hello World:  2021-07-20 15:13:00
Hello World:  2021-07-20 15:13:30
Hello World:  2021-07-20 15:14:00
Hello World:  2021-07-20 15:14:30
Hello World:  2021-07-20 15:15:00

3.3 cron class crontab expression

"""
When the time parameter is omitted, the parameter is set to before explicitly specifying the parameter*,
The parameters are then set to the minimum value. week and day_of_week The minimum value is*. 

For example:
Set up day=1, minute=20 Equivalent to Settings year='*', month='*', day=1, week='*', 
day_of_week='*', hour='*', minute=20, second=0,
It is the first day of each month and triggers when the minute reaches 20.
"""
# Note the order of parameters
class apscheduler.triggers.cron.CronTrigger(
year=None, 
month=None, 
day=None, 
week=None, 
day_of_week=None, 
hour=None, 
minute=None,
second=None, 
start_date=None, 
end_date=None, 
timezone=None, 
jitter=None)	# Vibration parameters

Keywords: Python

Added by the_reverend on Sun, 16 Jan 2022 01:31:12 +0200