How to run a cron job every 30 seconds

Updated November 6, 2026

Cron can’t run anything more often than once a minute: the smallest field in a crontab line is the minute. There are still several reliable ways to run a job every 30, 15 or 10 seconds. Which one fits depends on how long the job takes and whether two runs may overlap.

Two crontab lines with sleep

The most common trick: run the job at the start of every minute, and again 30 seconds later.

* * * * * /srv/poll.sh
* * * * * sleep 30; /srv/poll.sh

It is simple and survives reboots like any cron job. The second run starts 30 seconds after the minute, not 30 seconds after the first run ended, so if poll.sh can take longer than 30 seconds, two copies will run at once. Prevent that with flock:

* * * * * flock -n /tmp/poll.lock /srv/poll.sh
* * * * * sleep 30; flock -n /tmp/poll.lock /srv/poll.sh

-n makes the second copy give up right away instead of waiting, so runs are skipped rather than queued.

A loop inside one minute

For 15 or 10 seconds, more lines get messy. Use a loop instead:

# every 15 seconds
* * * * * for i in 1 2 3 4; do /srv/poll.sh; sleep 15; done

Here each run starts after the previous one finished plus 15 seconds, so a slow run pushes the next ones later. If the loop doesn’t fit in a minute, it overlaps with the next minute’s loop. That’s fine for quick jobs and a reason to pick another option for slow ones.

A systemd timer

systemd timers support seconds directly, and a timer never starts a service that is still running:

# /etc/systemd/system/poll.timer
[Timer]
OnBootSec=30s
OnUnitActiveSec=30s
AccuracySec=1s

[Install]
WantedBy=timers.target

AccuracySec=1s matters: by default systemd may delay a timer by up to a minute to save power, which defeats a 30-second interval. The service itself is a normal Type=oneshot unit; the systemd timers guide shows a complete one with pings for success and failure.

A long-running worker

If the job runs every few seconds, starting a new process each time costs more than the work. A small loop kept alive by systemd, Docker or Kubernetes is often cleaner:

#!/bin/sh
while true; do
  /srv/poll.sh
  sleep 30
done

Run it with Restart=always in a systemd service, or restart: unless-stopped in Docker Compose. Then the process supervisor, not cron, keeps it running.

Which one to choose

OptionGood forWatch out for
Two lines with sleepQuick jobs every 30 secondsOverlaps without flock
Loop in one lineQuick jobs every 10–20 secondsDrift and overlap when a run is slow
systemd timerAny interval, no overlapsSet AccuracySec
Long-running workerEvery few secondsNeeds a supervisor to restart it

Monitoring a job that runs this often

A job that runs every 30 seconds fails loudly when it fails, but it can also just stop: the timer is disabled, the worker dies, the server is replaced and the crontab isn’t restored. A heartbeat catches all of these. You don’t need a ping on every run; one ping a minute is enough to know the job is alive.

In Heartcron, create a check with a 1-minute period and a short grace period, and ping from the first crontab line only:

heartcron checks create poller --every 1m --grace 2m

* * * * * flock -n /tmp/poll.lock /srv/poll.sh && curl -fsS -m 10 --retry 3 https://ping.heartcron.com/<uuid> > /dev/null
* * * * * sleep 30; flock -n /tmp/poll.lock /srv/poll.sh

If pings stop for more than three minutes, you get an alert by email, Telegram, Slack or Discord. Every signal, including /fail for errors, is in the docs. For schedules of a minute and longer, the cron expression explainer shows exactly when a line will run.

More guides