Schedule Jobs with at, cron, and systemd Timers

LinuxBeginner
Practice Now

Introduction

Linux administrators schedule work in several ways. The at command schedules one-time jobs, cron schedules recurring jobs from simple time fields, and systemd timers schedule systemd services with systemd's dependency and logging model.

In this lab, you will create one command script and schedule it three ways. You will inspect the scheduler services, queue a one-time at job, configure a cron drop-in file, create a systemd service and timer pair, and manually test the service behind the timer.

Inspect Schedulers and Create a Job Script

In this step, you will confirm that the scheduler services are running and create one small script that all scheduled jobs will call.

Move into the project directory.

cd /home/labex/project

Check the one-time job daemon and the cron daemon. systemctl is-active prints active when a service is currently running.

systemctl is-active atd crond

List existing systemd timers. The output shows the next run time, the timer unit, and the service unit it activates.

systemctl list-timers --all --no-pager | sed -n '1,10p'

Create a script that appends a timestamped line to a log file. The first argument, $1, becomes the label that identifies which scheduler ran the script.

cat > /home/labex/project/scheduled-note.sh <<'EOF'
#!/bin/bash
echo "$(date '+%F %T') $1" >> /home/labex/project/schedule-events.log
EOF

Make the script executable.

chmod 755 /home/labex/project/scheduled-note.sh

Run the script manually once.

/home/labex/project/scheduled-note.sh manual-run
tail -n 1 /home/labex/project/schedule-events.log

The log line should end with manual-run.

Queue a One-Time at Job

In this step, you will schedule a one-time job with at. This is useful for work that should happen once at a future time, such as a temporary maintenance task.

Queue the script to run two hours from now. The command to run is piped into at.

echo "/home/labex/project/scheduled-note.sh at-job" | at now + 2 hours

List the queued jobs.

atq

Save the job id from the first atq line. The job id is the first field in the output.

job_id="$(atq | awk 'NR==1 {print $1}')"
echo "$job_id" > /home/labex/project/at-job.id
cat /home/labex/project/at-job.id

Inspect the queued job content. at -c prints the generated job script; the final lines should include the command you queued.

at -c "$job_id" | tail -n 12

Configure a cron Drop-In File

In this step, you will configure a recurring cron job with a file in /etc/cron.d. Files in this directory include a user field, so the system knows which account should run the command.

Create a cron file that runs the script every minute as the labex user. The PATH line gives cron a predictable command search path.

sudo tee /etc/cron.d/rhcsa-schedule-demo >/dev/null <<'EOF'
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
* * * * * labex /home/labex/project/scheduled-note.sh cron-job
EOF

Set the file mode to 644. Cron files must be readable and should not be writable by ordinary users.

sudo chmod 644 /etc/cron.d/rhcsa-schedule-demo

Reload crond so it notices the file immediately.

sudo systemctl reload crond

Inspect the file you created.

sudo cat /etc/cron.d/rhcsa-schedule-demo

The schedule fields * * * * * mean every minute.

Create a systemd Service and Timer

In this step, you will create a systemd service and a timer that activates it. A timer does not run a command directly; it starts a service unit.

System services should execute commands from system executable paths, not from a user's working directory. Install a copy of your script under /usr/local/bin.

sudo install -m 755 /home/labex/project/scheduled-note.sh /usr/local/bin/rhcsa-scheduled-note
sudo restorecon /usr/local/bin/rhcsa-scheduled-note 2>/dev/null || true
ls -l /usr/local/bin/rhcsa-scheduled-note

Create the service unit. Type=oneshot is appropriate for a command that runs and exits.

sudo tee /etc/systemd/system/rhcsa-schedule-demo.service >/dev/null <<'EOF'
[Unit]
Description=Write RHCSA schedule demo entry

[Service]
Type=oneshot
User=labex
ExecStart=/usr/local/bin/rhcsa-scheduled-note timer-job
EOF

Create the timer unit. OnBootSec=2min schedules a first run after boot, and OnUnitActiveSec=5min schedules later runs relative to the previous activation.

sudo tee /etc/systemd/system/rhcsa-schedule-demo.timer >/dev/null <<'EOF'
[Unit]
Description=Run RHCSA schedule demo periodically

[Timer]
OnBootSec=2min
OnUnitActiveSec=5min
Unit=rhcsa-schedule-demo.service

[Install]
WantedBy=timers.target
EOF

Reload systemd, enable the timer for boot, and then start it now. Splitting enable and start makes it clear which command makes the timer persistent and which command activates it immediately.

sudo systemctl daemon-reload
sudo systemctl enable rhcsa-schedule-demo.timer
sudo systemctl start rhcsa-schedule-demo.timer

Inspect the timer.

systemctl list-timers rhcsa-schedule-demo.timer --all --no-pager

The timer should appear in the list, and it should activate rhcsa-schedule-demo.service.

Test the Timer Service and Remove the at Job

In this step, you will manually start the service used by the timer. This verifies the command immediately without waiting for the next scheduled timer activation. You will also remove the queued at job because it was only for practice.

Start the service manually.

sudo systemctl start rhcsa-schedule-demo.service

Inspect the log.

tail -n 5 /home/labex/project/schedule-events.log

One line should end with timer-job.

Remove the queued at job by using the job id saved earlier.

job_id="$(cat /home/labex/project/at-job.id)"
atrm "$job_id"

Confirm the job is no longer queued.

atq

Summary

You practiced three scheduling methods. You inspected atd, crond, and systemd timers, created a reusable scheduled command script, queued and inspected a one-time at job, configured a recurring cron drop-in file, installed a service-safe command under /usr/local/bin, created a systemd service and timer pair, manually tested the timer service, and removed the temporary at job.