php[architect] logo

Want to check out an issue? Sign up to receive a special offer.

Scheduling Tasks With CRON

Posted by on September 1, 2023


 

 

 

As developers, most of the time, our websites perform some kind of action based on a user clicking a button or typing some data, but there are some things we need to be able to do outside of the normal web request flow. For example, we should be running our backups at least once a day, we should have something automatically applying our system updates, and we’ll want to send an email to users who haven’t logged in recently, enticing them to come back.

The cron system installed on almost every Unix-based operating system provides the solution for this.

In this article, we’ll discuss what cron can do for us, how to create a basic schedule job and some more advanced topics related to cron.

What Cron Can Do For Us

In Unix system administration, the cron system is an invaluable tool for scheduling and automating tasks. Cron is a time-based job scheduler in Unix. It allows users to schedule commands or scripts to run at specific times or at intervals.

The cron system consists of two main components the cron daemon (crond) and the CRON TABle (crontab). The cron daemon runs continuously in the background and executes scheduled tasks, while the cron table contains the list of tasks and their scheduling information.

How to Create a Cron Job

Each user on a Unix system can have their crontab file.

To create or modify cron jobs, you need to work with the crontab command. I should say there may be differences in the way my crontab command works in comparison to how your crontab works.

To start we’ll check to see what’s currently in our crontab by running crontab -l

$ crontab -l
crontab: no crontab for scottkeck-warren

In this case, we have nothing.

Now to create or edit the crontab we’ll run crontab -e

$ crontab -e
crontab: no crontab for scottkeck-warren - using an empty one

This should launch into your terminal’s default editor. For my setup, this is vim.

Each row of the file will be a unique cron entry and each cron entry consists of six fields that define when and how a task should run.

To get started we’ll use a super simple example which will be to enter 5 asterisks and then a command to run date and appended the results to the “cron.log” file in the home directory of the current user.

* * * * * date >> ~/cron.log

This will run the date command every minute.

Save the file and exit the editor (:qw in vim) and you should see the following message:

crontab: installing new crontab

To check our crontab we can run crontab with the -l argument to have it list the contents.

$ crontab -l
* * * * * date >> ~/cron.log

Now let’s see our results. We can use the tail command with the -f argument to see the output of our cron job in real-time.

$ tail -f ~/cron.log
Tue Jul  4 12:55:00 EDT 2023
Tue Jul  4 12:56:00 EDT 2023

I don’t want to have this running forever so I’ll reset my crontab using the -r command line switch. Be careful with this as it deletes your crontab without prompting to make sure that’s what you want.

crontab -r

Just to complete our roundup of the crontab command there’s one more switch that’s important to discuss and that’s the -u argument which will allow us to edit someone else’s crontab file.

For example, to edit the www-data user’s file we would run:

sudo crontab -e -uwww-data

More after this word from our sponsor

How to Schedule Cron Jobs

We did the most basic cron job to get us started but cron is more powerful than just running the same job every minute. I glossed over the significance of the five asterisks in the job that we created but those five asterisks are the five fields that control when our job should run.

The fields control:

  1. Minute (0-59)
  2. Hour (0-23)
  3. Day of the month (1-31)
  4. Month (1-12)
  5. Day of the week (0-7, where both 0 and 7 represent Sunday for some reason)

Each date and time field can have multiple values separated by commas or specified as ranges using hyphens (-). We can also use an asterisk (*) to represent all possible values for a field and a forward slash (/) specifies a step value within a range.

Let’s work through some examples.

To run a command every day at 7:00 AM we would put a 0 in the minute field, a 7 in the hour field, and asterisks in every other field.

0 7 * * * date >> ~/cron.log

To run a command every 15 minutes we would use asterisk forward slash 15 and then asterisks in the other four fields.

*/15 * * * * date >> ~/cron.log

To run a script every Monday at 8:00 PM we would put a 1 in the day of the week field.

0 20 * * 1 date >> ~/cron.log

Extend that to Monday and Wednesday we’ll make it 1,3

0 20 * * 1,3 date >> ~/cron.log

To run a command on the 1st and 15th of every month at midnight, we’ll put 1,15 in the day of the month field and 0s for the hour and minute, and asterisks for the final two fields.

0 0 1,15 * * date >> ~/cron.log

Finally, to run every January 1st at midnight we’ll to 0s in the hour and minutes again and 1’s in the month and day of the month fields.

0 0 1 1 * date >> ~/cron.log

System Level Cron

On top of the fact that every user has their crontab, there is also a system-wide crontab file that’s usually located at /etc/crontab. This is where I like to put all of my cron jobs that aren’t related to a specific user and are instead something that needs to happen at a system level like backups.

To make changes to this crontab we’ll edit the file directly using vim /etc/crontab.

This file has an extra field that indicates the user under which the command should be run. This acts just as if the user had logged in so the command will get the same permissions. I highly recommend you NOT run a command as root if you can prevent it but sometimes it’s unavoidable.

# m h dom mon dow user  command
1 45 * * 1 root certbot renew

Systemd

On some variants of Unix, a new system is starting to replace cron called systemd. It does a lot more than cron does and is significantly more powerful but it’s not as widespread and not always available if you’re using some kind of shared hosting. That being said I’m sure we’ll cover it in a future article.

Managing Your Cron Jobs

As an application developer, you might find it a challenge to manage all your cron jobs inside a single file. I once managed an application that had 50+ scheduled jobs that we maintained through cron. Because there was no peer review of this file every so often someone would accidentally delete one of the jobs and it would fail until someone noticed. Usually, it was a customer asking why they hadn’t received something that made us look into it.

There are two solutions to this problem.

The first is that you can manage your crontab file inside of your source code using something easy like just copying the file over to the server or use something a little more complex like Ansible, Puppet, or Docker. This is an acceptable solution but it does complicate our deployment a little I don’t like to do that.

The second solution is to manage your jobs inside your application. You can have a single cron job that you don’t have to touch and then configure the scheduled jobs using your application code. This is the approach that Laravel uses, and it can be very powerful as we’re given extra control over how and where the jobs will run.

What You Need To Know

  • Cron is a Unix tool for scheduling and automating tasks
  • Use crontab command to modify
  • Use application code to manage jobs for more power/control

Tags: ,
 

Leave a comment

Use the form below to leave a comment: