Python APScheduler Tutorial – Advanced Scheduler

In this Python APScheduler Tutorial, we will explore the APScheduler library, also known as the Advanced Python Scheduler. As the name implies, this is one of the most advanced scheduler libraries available in Python with a variety of different features and scheduling options.


Introduction to APScheduler

As APScheduler is not included in the Python Standard Library, it needs to be downloaded separately. You can do this using pip.

pip install apscheduler

If you are interested in a Scheduling library that is part of the Standard Library, check out this one.

There are 4 main components that make up the Python APScheduler Library.

  • triggers – Responsible for scheduling logic, and deciding when the job is to be executed.
  • job stores – As the name implies, this defines the area where the all the scheduled jobs are stored. The default store simply stores all jobs within memory. But for more specialized use cases, you can have them stored in databases (like SQL).
  • executors – handle the running of the jobs.
  • schedulers – The backbone that binds everything together. There is typically only one scheduler per application.

This tutorial does not aim to cover all of these aspects, rather give you a good grasp over the basics of the Python APScheduler Library and demonstrate several use cases.


Choosing the right scheduler in APScheduler

Let’s take a look at the various types of Schedulers available in APScheduler.

  • BlockingScheduler: use when the scheduler is the only thing running in your process. (runs in the foreground)
  • BackgroundScheduler: use when you’re not using any of the frameworks below, and want the scheduler to run in the background inside your application. (Runs on a separate thread)
  • AsyncIOScheduler: use if your application uses the asyncio module
  • GeventScheduler: use if your application uses gevent
  • TornadoScheduler: use if you’re building a Tornado application
  • TwistedScheduler: use if you’re building a Twisted application
  • QtScheduler: use if you’re building a Qt application

Most of these are meant to be used with Frameworks, so if you aren’t using any frameworks, you can ignore most of them. For regular use cases, the BackgroundScheduler is a good choice. We will be using it for most of this Python APScheduler tutorial.


Selecting the Right Trigger in APScheduler

When you schedule a job, you need to choose a trigger for it. The trigger determines the logic by which the scheduling dates/times are calculated for when the job will be scheduled to execute.

The Python APScheduler Library comes with three built-in trigger types to pick from:

  • date: use when you want to run the job only once at a certain time.
  • interval: use when you want to run the job at fixed intervals of time.
  • cron: when you want to periodically run the job at certain time(s) of the day.

Understanding the use of each one of these is pretty important. Hence, we will demonstrate the use of each one of these throughout this Python APScheduler tutorial. (Don’t worry about understanding how to use them right now)


Scheduling jobs with APScheduler

Let’s take a look at how to add jobs to our Scheduler. Remember, a “job” is a task that we are assigning the scheduler such as executing a specific function.

Creating the Scheduler

Before doing anything, we need to set up a scheduler. We aren’t using any special frameworks, and just want to get a simple scheduler up and running. (This will be more than enough for most use cases).

from apscheduler.schedulers.background import BackgroundScheduler

# Creates a default Background Scheduler
sched = BackgroundScheduler()

This scheduler has uses the default Job store (memory based) and maximum thread count of 10.


Adding jobs to the Scheduler

The most common way of adding jobs to scheduler is through the use of the add_job() function. This function also returns a Job object, which can be used in further processing later. (Such as modifying or removing the job from scheduler)

The following code executes the prompt() function every 5 seconds.

def prompt():
    print("Executing Task...")

sched.add_job(prompt, 'interval', seconds = 5)

.As you can see, the first parameter in the add_job(), we passed the name of the function to be called. The second parameter specifies the trigger. The parameters after this define the scheduling logic. There are many parameters, like seconds, minutes, hours, day, week, month and year.

The complete code for the above example is as follows. You will notice that we use an infinite loop at the end of this code. We will elaborate on this in the next section.

from time import sleep
from apscheduler.schedulers.background import BackgroundScheduler

# Creates a default Background Scheduler
sched = BackgroundScheduler()

def prompt():
    print("Executing Task...")

sched.add_job(prompt,'interval', seconds=5)

# Starts the Scheduled jobs
sched.start()

# Runs an infinite loop
while True:
    sleep(1)

Try running the code to see the output for yourself!


We haven’t covered the AsyncIOScheduler in this tutorial, but have a separate article dedicated solely to it. Check it out if you are interested.


BackgroundScheduler vs BlockingScheduler

Let’s take a quick look at the difference between the Background and Blocking Scheduler. The background scheduler, as the name implies, runs a separate thread from the main thread. Once the main thread finishes execution, the thread on which the Background Scheduler is running also closes. This happens even if there are some scheduled jobs to execute.

from apscheduler.schedulers.background import BackgroundScheduler

# Creates a default Background Scheduler
sched = BackgroundScheduler()

def prompt():
    print("Executing Task...")

sched.add_job(prompt,'interval', seconds=5)
sched.start()

If you run the above code (which doesn’t have the infinite loop), you will notice there is no output. This is because the main thread finished execution after calling the start() function.

This is why in the previous example we used an infinite loop, to prevent the main thread from closing.

With the BlockingScheduler however, the scheduler runs on the main thread. Hence until the scheduler is stopped on the main thread using the shutdown() function, the main thread will not close.

The code in the below example uses the BlockingScheduler instead of the BackgroundScheduler. Run the code, and notice how it will keep running, even though there is no infinite loop.

from time import sleep
from apscheduler.schedulers.background import BlockingScheduler

# Creates a default Background Scheduler
sched = BlockingScheduler()

def prompt():
    print("Executing Task...")

sched.add_job(prompt,'interval', seconds=5)

sched.start()

Interested in exploring other Scheduling Libraries in Python? Check out this light-weight alternative for Scheduling in Python!


Date and Cron Triggers in APScheduler

Now let’s take a look at an example for both the date and cron triggers.

Date Trigger

The date trigger is used to execute a job at a specific point in time. This kind of job only runs once.

The below code showcases such an example. You can also pass in arguments to the function that you are calling using the args parameter. This is something that is common amongst all three triggers, not just date.

The below code makes use of the date trigger. We have included three different ways in which you can pick the value for the run_date parameter.

from time import sleep
from datetime import date, datetime
from apscheduler.schedulers.background import BlockingScheduler

# Creates a default Background Scheduler
sched = BlockingScheduler()

def job(text):    
    print(text)

# In 2022-4-30 Run once job Method
sched.add_job(job, 'date', run_date = date(2019, 8, 30),
                           args=['Job 1'])

# In 2022-4-30 12:00:00 Run once job Method
sched.add_job(job, 'date', run_date = datetime(2022, 4, 30, 12, 0, 0), 
                           args=['Job 2'])

# In 2022-4-30 08:00:00 Run once job Method
sched.add_job(job, 'date', run_date = '2022-4-30 08:00:00',
                           args=['Job 2'])

sched.start()

Cron Trigger

Now let’s take a look at the cron trigger. This is a very popular (and powerful) type of trigger, that is used to periodically schedule tasks. For example, executing a task at a certain time every day, or having a task execute on certain days (like monday to friday).

Let’s take a look at 5 different examples, each demonstrating a different way in which cron jobs can be scheduled with APScheduler.

# Runs every minute at 17 o'clock a day job Method
sched.add_job(job, 'cron', hour= 17, minute= '*',
                                      args= ['job 1'])

The above code uses the special character “*”. This will cause the job to be repeated every minute. If the “*” was placed in the seconds parameter, it would repeat every second.

# Runs every 5 minutes at 17 o'clock a day 
sched.add_job(job, 'cron', hour= 17, minute= '*/5',
                                     args= ['job 2'])

The above code is a variation of the first one, but utilizes the */n format. This causes the job to be repeated every “n” number of times.

# Runs once a day at 17:25 and 18:25 job Method
sched.add_job(job, 'cron', hour='17-18', minute= '25',
                                     args= ['job 3'])

This code shows how you can specify a range of values. Hence allowing us to have the code execute over a span of 2 hours, instead of just one.

# Schedules job to be run on the third occurrence of Friday
# on the months June, July, August, November and December
# at 00:00, 01:00, 02:00, 03:00 and 04:00
sched.add_job(job, 'cron', month= '6-8,11-12', day= '3rd fri',
                           hour= '0-4', args= ['job 4'])

This code demonstrates two new things. First, it shows you can specify multiple ranges, simply by adding commas between them. Secondly, it shows the use of the xth y format, which causes the job to run on the x -th occurrence of weekday y within the month.

There is another option you can make use of, called last. Using last alone causes the code to be run on the last day of the month, otherwise last fri will schedule the job for the last friday of the month.

# Runs from Monday to Friday at 6:30AM until 2022-06-30 00:00:00
sched.add_job(job, 'cron', day_of_week= 'mon-fri', hour= 6,
                           minute= 30, end_date= '2022-06-30',
                           args= ['job 5'])

The above code mainly show cases the fact that you can use the end_date option to stop the code from executing once a certain date has been reached.

If you want to learn more about the Cron Trigger in APScheduler, then do take a look at our dedicated tutorial for Cron, which covers it in even more detail.


Removing Jobs

Compared to the complexity and number of options available when adding jobs, removing jobs is a much easier task. All you need is either the job object, or the job ID that we assigned when creating the job.

Earlier we didn’t bother storing the returned job object from add_job() anywhere. If we want to ability to remove jobs later though, we will have to do this.

jobObj = sched.add_job(myfunc, 'interval', minutes=2)
jobObj.remove()

Alternatively, you can just assign an ID, which you can use to remove it later.

sched.add_job(task, 'interval', minutes=2, id='random_job_id')
sched.remove_job('random_job_id')

Closing the Scheduler

Remember, that once you are done with the scheduler, you can shut it down by using the shutdown() function.

scheduler.shutdown()

This marks the end of the Python APScheduler Tutorial. Any suggestions or contributions for CodersLegacy are more than welcome. Questions regarding the tutorial content can be asked in the comments section below.

Subscribe
Notify of
guest
2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments