# Scheduling Jobs with Systemd

In a previous post, I discussed some of the different options available to you on most POSIX system to automate the running of jobs on schedule. Here is a brief recipe on how to actually use the modern/trendy and actually functionally beneficial “systemd” to do this as a normal (non-root).

In addition to the job file or script itself, you will need to create two files: a timer file and a service file (also referred to as timer unit and service unit).

1. Let us start with creating the job file. In practice, this might be your backup, cleanup, indexing, etc. script Here, it is going to be a little less useful, but perhaps much more iconic. Create, “~/.local/bin/hello-world.sh”:

# /bin/sh
echo "Hello, world: $(date)" >> "$HOME/scheduledjob.txt"
2. Now, create the service unit which will call the above script, in “~/.config/systemd/user/hello-world.timer”:

[Unit]
Description=A job to greet the world

[Service]
Type=simple
ExecStart=/home/you/.local/bin/hello-world.sh

[Install]
WantedBy=default.target

Important things to note:

• The part to the executable must be absolute, with no variables!
• “user” in the file path “~/.config/systemd/user/…” path above is literally “user”, not your user name.
3. Create the timer unit which will actually schedule the service unit above in “~/.config/systemd/user/hello-world.timer”:

[Unit]
Description=Schedule a greeting every 1 minute
RefuseManualStart=no        # Allow manual starts
RefuseManualStop=no         # Allow manual stops

[Timer]
# Execute job if it missed a run due to machine being off
Persistent=true
# Run 120 seconds after boot for the first time
OnBootSec=120
# Run every 1 minute thereafter
OnUnitActiveSec=60
# File describing job to execute
Unit=hello-world.service

[Install]
WantedBy=timers.target

While this example uses “OnUnitActiveSec” to specify the schedule, “OnCalendar” offers you incredible control and flexibility in expressing the timing if you need it. For example:

# run on the minute of every minute every hour of every day
OnCalender=*-*-* *:*:00

# run on the hour of every hour of every day
OnCalender=*-*-* *:00:00

# run every day
OnCalender=*-*-* 00:00:00

# run 11:12:13 of the first or fifth day of any month of the year 2012, but only if that day is a Thursday or Friday
OnCalender=Thu,Fri 2012-*-1,5 11:12:13

4. All our components are in place, but before we actually schedule the service, we want to make sure it works.

First, we have to enable to service:

$systemctl --user enable hello-world.service which should result in something like: Created symlink /home/you/.config/systemd/user/default.target.wants/hello-world.service → /home/you/.config/systemd/user/hello-world.service. Then, we do a test run of the job: $ systemctl --user start hello-world.service

And check to make sure all is as wanted/expected. If not, then debug the script and repeat, remembering to enable the service again if the problem was in the service file (as opposed to the script that the service file invokes).

Otherwise …

5. Actually schedule it!

    $systemctl --user enable hello-world.timer$ systemctl --user start hello-world.timer
6. Check/monitor the service:

$systemctl --user status hello-world$ systemctl --user list-unit-files
7. View the logs:

$journalctl --user --unit hello-world.service$ journalctl --user --unit hello-world.timer

Or, to see only log messages for the current boot:

$journalctl --user --unit hello-world.service --boot$ journalctl --user --unit hello-world.timer --boot
8. If we want to manually run the backup:

$systemctl --user start hello-world.service 9. Or manually stop it: $ systemctl --user stop hello-world.service
10. Permanently stopping/disabling the timer and service:

$systemctl --user stop hello-world.timer$ systemctl --user disable hello-world.timer
$systemctl --user stop hello-world.service$ systemctl --user disable hello-world.service
$systemctl --user daemon-reload$ systemctl --user reset-failed
11. You can see a practical example of this system in action driving a cloud-based backup system here.

12. References:

Share