DEV Community

Damjan Dimitrov
Damjan Dimitrov

Posted on

11 2

Python Scheduler: A cron job replacement

In this post I would like to show you a more convenient way of scheduling tasks to execute on a given time period.

Cron jobs are commands which are performed in a set time interval, it can be every minute, every hour, every third day, once a week etc.
Sometimes the process of creating and setting up a cron job might appear to be tedious and complicated. I've found an awesome python module for doing exactly what a cron job does but in a way cooler and more fun way.

The module is called schedule and according to its official documentation, it is designed to be very understandable by a human. Here's how it looks:

import schedule
import time
def job():
print("I'm working...")
schedule.every(10).minutes.do(job)
schedule.every().hour.do(job)
schedule.every().day.at("10:30").do(job)
schedule.every().monday.do(job)
schedule.every().wednesday.at("13:15").do(job)
schedule.every().minute.at(":17").do(job)
while True:
schedule.run_pending()
time.sleep(1)
view raw schedule.py hosted with ❤ by GitHub

Now, let's say we have a real life problem we need to solve and keep doing that periodically. As an example, I've made a script which checks for empty folders in a given path. This might appear to be a mess for someone who forgets to delete empty folders, keeps rearranging files and other scenarios. This is how the schedule module looks like in action:

#!/usr/bin/env python3
import os
import schedule
# Execute a system command to display a toast notification with a custom message
def notify(title, message):
os.system("""
osascript -e 'display notification "{}" with title "{}"'
""".format(message, title))
# Delete all empty folders in a given directory
def delete_empty_folders():
notify('Script', 'Script is currently running')
path = '/enter/path/here'
os.chdir(path) # Change working directory to the path
directory = os.walk(path) # Scan directory for its contents
content = next(directory)
for folder in content[1]: # Loop through each folder in the path
if not os.listdir(folder): # If it is empty remove it
os.rmdir(folder)
schedule.every().day.do(delete_empty_folders)
while True:
schedule.run_pending()
view raw scheduler.py hosted with ❤ by GitHub

Now, the last thing we need to consider: the scheduler is running only as long as we have our program open and running. When we close or stop the program, the scheduler is cut off and no longer checks for the time interval in the background.
As a solution for this, we can use the nohup command, which stands for no hangup and makes a process immune to hangups (in our case the hangup means stopping the script from running).
We have our scheduler.py file ready with the task we want to be executing in our timeline. These are the steps you should take in order to have the desired result:

  • Install the schedule module via pip by running pip install schedule , preferrably in your virtual environment
  • At the top of your script add #!/usr/bin/env python3 . This step is necessary if you have multiple versions of Python installed and /usr/bin/env will ensure that the first Python interpreter in your $PATH environment variable is taken.
  • In the terminal, run chmod +x scheduler.py , which will grant the required file permissions for continuous execution
  • Run the command nohup /path/to/scheduler.py & . The '&' symbol ensures that your script will run in the background as a system process.

Congrats, you now have your script running in the background. You can feel free to close the terminal and do something else while your script will check for the time period uninterruptedly. If you want to stop script from running, you can list the processes and find its id with the command

ps ax | grep scheduler.py

which shows you the process' PID and then run

kill PID

Source

Note: This was developed and tested only on a MacOS system

AWS GenAI LIVE image

Real challenges. Real solutions. Real talk.

From technical discussions to philosophical debates, AWS and AWS Partners examine the impact and evolution of gen AI.

Learn more

Top comments (3)

Collapse
 
aderchox profile image
aderchox • Edited

Good one, and explained well, thanks. But it doesn't seem to be as flexible as systemd timers (or even cron). E.g., what if the system reboots? Then we'll have to either manually run nohup /path/to/scheduler.py & again or we'll have to add a cron / systemd timer in order to trigger that script at the startup which makes the use of that library questionable in the first place. Or as another example, if we want the job to run as soon as a certain destination is pingable. Not that this latter one is 'impossible' with Python, but it's not as 'out-of-the-box' as it's in systemd.
Of course it's more 'portable' but that's sometimes not needed beyond theory.

Collapse
 
damjand profile image
Damjan Dimitrov

I agree with you, it has its advantages and disadvantages. When using this library it's preferable to use it in a remote server which is expected to have a nearly or completely uninterrupted uptime, such as a build server for an application. It might also become heavy on the system if used on a local machine where other work is also being done.

Collapse
 
aabiseverywhere profile image
Aabishkar Wagle

Good one. Thanks.

AWS GenAI LIVE image

How is generative AI increasing efficiency?

Join AWS GenAI LIVE! to find out how gen AI is reshaping productivity, streamlining processes, and driving innovation.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay