CronDrive
Guides

How to run a cron job every 30 seconds or less

Updated 16 October 2026

A crontab line runs at most once a minute: the expression has no field for the seconds. To run a job more often, there are two ways: several runs inside each minute, from the crontab, or a systemd timer, which does have seconds.

Every 30 seconds, with two lines

* * * * * /path/to/job.sh
* * * * * sleep 30; /path/to/job.sh

The first line runs at the start of each minute, and the second waits 30 seconds before running. Cron starts both at the same time, so they don’t depend on each other.

Every 10 seconds, with a loop

* * * * * for i in 0 1 2 3 4 5; do /path/to/job.sh & sleep 10; done

The loop starts the job six times a minute, 10 seconds apart. The & starts each run without waiting for the previous one to end, so the job’s own duration isn’t added to the 10 seconds of waiting. Because of that, if a run takes longer than 10 seconds, two copies run at the same time: flock prevents it.

With a systemd timer

A systemd timer accepts seconds, and it behaves differently from the loop: a time that arrives while the service is still active doesn’t start another copy. Choose the one that fits your job: with the loop, runs can overlap; with the timer, a slow run delays the next one. Two files, /etc/systemd/system/job.service:

[Unit]
Description=Job every 10 seconds

[Service]
Type=oneshot
ExecStart=/path/to/job.sh

And /etc/systemd/system/job.timer:

[Unit]
Description=Run job.service every 10 seconds

[Timer]
OnCalendar=*:*:0/10
AccuracySec=1s

[Install]
WantedBy=timers.target

Then:

sudo systemctl daemon-reload
sudo systemctl enable --now job.timer
systemctl list-timers job.timer
  • AccuracySec=1s matters. By default, a timer can fire up to a minute after its time, to group wake-ups: for a job every 10 seconds, that’s no use.
  • systemd-analyze calendar "*:*:0/10" shows the next times, to check the expression.
  • The output goes to the journal: journalctl -u job.service.

When it’s better not to schedule it

A job that has to run every second or two is usually better as a process that stays running, with a loop and its own pause, supervised by systemd. Starting a new process every few seconds also costs: the interpreter, the connections, the configuration.

If you came from Spring or Quartz, an expression with seconds, like */10 * * * * *, has no equivalent in crontab: the cron tester tells you which ones do.

Watch it by the minute

CronDrive checks the schedule by the minute. You can monitor the run of each minute, with the calls in the first of the two lines, but that doesn’t check the run in between. If you need to detect every failure or every missing run, this check by the minute isn’t enough.

CronDrive emails you, or posts to Slack, when a job with this schedule fails, or doesn't start or finish on time. Free for up to 15 jobs.

What you'd see with this schedule

An example with the last runs of this schedule and made-up results: one failed and one didn't run.

Times in UTC.

Due
Saturday 17 October 2026
02:02 On time Started 02:02, finished 02:02, took <1 min.
02:01 Didn't run Alerts sent at 02:02 and 02:02.
02:00 On time Started 02:00, finished 02:00, took <1 min.
01:59 Failed with code 1 Alert sent at 01:59. Started 01:59, finished 01:59, took <1 min.
01:58 On time Started 01:58, finished 01:58, took <1 min.
01:57 On time Started 01:57, finished 01:57, took <1 min.

The alert of the failed run

Email from CronDrive, Sat 17 Oct, 01:59

Failed (exit code 1): "Your job"

The job "Your job" failed with exit code 1.

If you connect Slack, the same message goes to your channel.

The change in your crontab

* * * * * curl -fsS -m 10 https://job.crondrive.com/uG2Exw/start/$$; /path/to/job.sh; curl -fsS -m 10 https://job.crondrive.com/uG2Exw/end/$?/$$

Two calls around your command, in the same line. Your job's line comes with its own token.

Monitor this schedule