Skip to main content

Automation and Task Ranking

Automation tools are not interchangeable. The right tool depends on reliability requirements, observability needs, and the kind of trigger you want (time, event, or process supervision). This page ranks common Linux automation approaches using operational criteria, then gives you a selection guide.

Quick Summary
  • For modern VPS hosts: prefer systemd timers for scheduled work.
  • For file-change triggers: prefer systemd.path.
  • Use cron when portability matters or when systemd is not available.
  • Use supervisors for long-running processes (not scheduled batch jobs).

Ranking rubric (what actually matters)

This rubric is based on production behavior.

CriterionWhy it matters
Logging and auditabilityyou need a timeline during incidents
Missed-run handlingservers reboot; jobs should not vanish
Dependency and orderingbackups should wait for mounts/services
Concurrency controloverlapping jobs cause corruption and load spikes
Security controlsleast privilege, resource limits, sandboxing
Portabilitysome distros/containers lack systemd
Debuggabilityfast root-cause when jobs fail

Tool ranking (practical default)

This ranking is a "default order" for VPS operations. It is not a universal truth.

ToolTrigger typeBest atWhy it ranks wellWhen it loses
systemd timertimescheduled jobslogs, missed-run support, dependenciesnon-systemd environments
systemd.patheventfile triggersstable unit model, no custom daemonsneeds systemd
crontimeportable schedulesubiquitous, simpleweak logging, missed runs
atone-timedelayed one-offsimple deferralnot for recurring workloads
anacrontimecatch-upruns jobs that were missedlimited scheduling model
supervisordprocesskeep runningrestarts, monitors long-livednot a scheduler

Quick selection guide

Use caseRecommended toolNotes
Daily backupssystemd timeradd dependencies and logs
Rotate/prune backupssystemd timer or cronadd locks + logs
"Run when a file appears"systemd.pathbuild reliable pipelines
"Run once later"atgood for maintenance window tasks
Keep a worker runningsupervisordor native systemd service

Cron improvements (what systemd fixes)

Cron is not "bad". It is just minimal. systemd timers improve on cron by default:

  • captured stdout/stderr in journald
  • missed run replay (Persistent=true)
  • dependencies (After=network-online.target)
  • explicit user and environment
  • resource limits

Example: cron vs timer for the same job

Cron

cron-example.txt
15 2 * * * /usr/local/bin/wp-backup-run >>/var/log/wp-backup.log 2>&1

systemd timer

/etc/systemd/system/wp-backup.service
[Unit]
Description=WordPress backup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/wp-backup-run
/etc/systemd/system/wp-backup.timer
[Unit]
Description=Run WordPress backup daily

[Timer]
OnCalendar=*-*-* 02:15:00
Persistent=true

[Install]
WantedBy=timers.target
enable-wp-backup-timer.sh
sudo systemctl daemon-reload
sudo systemctl enable --now wp-backup.timer
systemctl list-timers --all | rg -n 'wp-backup'

Notes by environment

  • Use systemd timers for scheduled tasks.
  • Use journald logs for post-mortem debugging.
  • Prefer unit dependencies over sleep loops.

systemd.path vs inotify (file triggers)

If your automation is triggered by files appearing or changing, you have two common approaches:

  • inotify-based scripts (inotifywait) that run continuously
  • systemd.path units that trigger a service

systemd.path is often easier to operate because it behaves like other systemd units.

Example: run a service when a file appears.

/etc/systemd/system/process-incoming.service
[Unit]
Description=Process incoming files

[Service]
Type=oneshot
ExecStart=/usr/local/bin/process-incoming
/etc/systemd/system/process-incoming.path
[Unit]
Description=Watch incoming directory

[Path]
PathExistsGlob=/srv/incoming/*

[Install]
WantedBy=multi-user.target
enable-systemd-path-trigger.sh
sudo systemctl daemon-reload
sudo systemctl enable --now process-incoming.path
systemctl status process-incoming.path --no-pager --full

Notes:

  • PathExistsGlob triggers when any file matches.
  • systemd.path is not a replacement for all real-time watchers, but it is stable for many ops pipelines.

Overlap control and job safety

Most automation incidents happen because two copies of the same job run at once. Pick one overlap strategy.

Lock files (cron or timers)

lock-with-flock-example.sh
flock -n /var/lock/myjob.lock /usr/local/bin/myjob

Queueing (one at a time)

If tasks can queue, use a queue tool.

  • ts (task spooler) for sequential job queues
  • a simple "run next" wrapper around a directory queue

Example with task spooler:

task-spooler-example.sh
ts /usr/local/bin/backup-run
ts /usr/local/bin/prune-backups
ts

systemd service-level constraints

systemd provides guardrails that cron does not:

  • RuntimeMaxSec= to prevent runaway jobs
  • StartLimitIntervalSec= and StartLimitBurst= to prevent crash loops
  • Nice= and resource limits
systemd-service-guardrails-example.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/myjob
RuntimeMaxSec=2h
Nice=10

One-shot vs long-running automation

Do not schedule a daemon with cron. Do not run a batch job under a process supervisor.

Workload typeCorrect tool class
Scheduled batch (backup, cleanup)cron or systemd timer
Triggered batch (file appears)systemd.path or watcher
Long-running workersystemd service / supervisord

Anti-patterns to avoid

  • Running backups from a WordPress plugin UI instead of a scheduler.
  • Using sleep in cron entries to add randomness (use timers with RandomizedDelaySec=).
  • Running destructive commands without a dry-run step.
  • Hiding failures by redirecting to /dev/null.
  • Scheduling jobs without locking (overlap is inevitable).

Practice lab

This lab installs a simple timer that writes a heartbeat log.

  1. Create a script.
lab-create-heartbeat-script.sh
sudo install -m 755 /dev/stdin /usr/local/bin/heartbeat <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
echo "[$(date -Is)] heartbeat" >> /var/log/heartbeat.log
EOF
  1. Create a service and timer.
/etc/systemd/system/heartbeat.service
[Unit]
Description=Write heartbeat log

[Service]
Type=oneshot
ExecStart=/usr/local/bin/heartbeat
/etc/systemd/system/heartbeat.timer
[Unit]
Description=Run heartbeat every minute

[Timer]
OnUnitActiveSec=60s
OnBootSec=30s
Persistent=true

[Install]
WantedBy=timers.target
lab-enable-heartbeat-timer.sh
sudo systemctl daemon-reload
sudo systemctl enable --now heartbeat.timer
systemctl list-timers --all | rg -n 'heartbeat'
  1. Check logs.
lab-check-heartbeat-log.sh
sudo tail -n 20 /var/log/heartbeat.log
journalctl -u heartbeat.service --since '10 minutes ago' --no-pager

Next steps

  • Cron fundamentals: opt/docker-data/apps/docusaurus/site/docs/server/linux-server/11-automation-task-execution/cron.mdx
  • Cron vs systemd: opt/docker-data/apps/docusaurus/site/docs/server/linux-server/11-automation-task-execution/cron-vs-systemd.mdx
  • Output and logs: opt/docker-data/apps/docusaurus/site/docs/server/linux-server/11-automation-task-execution/redirecting-output-and-logs.mdx