Back to Blog
How-To5 min read

How to Run a Cron Job Every 30 Seconds

Standard cron expressions only support minute-level granularity — there is no way to write "every 30 seconds" in a crontab. Here are five proven workarounds, from the simplest hack to production-grade solutions.

The Problem: Cron's 1-Minute Minimum

A cron expression has five fields: minute, hour, day of month, month, and day of week. The smallest unit is one minute. There is no "seconds" field. Writing * * * * * gives you every minute — that's as fast as cron goes.

If you need to run a task every 30 seconds, you need one of the workarounds below.

Method 1: The Sleep Trick (Most Popular)

The most common approach: create two crontab entries. The first runs your script at the top of each minute. The second waits 30 seconds, then runs the same script:

# Run every 30 seconds
* * * * * /path/to/script.sh
* * * * * sleep 30 && /path/to/script.sh

How it works: Cron fires both entries every minute. The first runs immediately (at second 0). The second sleeps for 30 seconds, then runs (at second 30). Result: your script executes twice per minute, 30 seconds apart.

Pros

  • Works on every Linux/Unix system
  • No extra packages or services needed
  • Easy to understand and set up

Cons

  • Two entries for one logical job — easy to forget one when editing
  • Minor timing drift (cron itself can have up to 1-second jitter)
  • Both entries run independently — no built-in overlap protection

Method 2: Bash Loop with Sleep

Instead of two crontab entries, use a single entry that runs a wrapper script. The wrapper executes your task, sleeps 30 seconds, and runs it again:

#!/bin/bash
# run-every-30s.sh
for i in 0 30; do
  /path/to/script.sh &
  sleep 30
done

Then add a single crontab entry:

* * * * * /path/to/run-every-30s.sh

The & runs the script in the background so the sleep doesn't block execution. The loop runs twice per minute (at second 0 and second 30), matching cron's one-minute interval.

Tip: Make sure run-every-30s.sh is executable: chmod +x /path/to/run-every-30s.sh

Method 3: systemd Timer

On modern Linux systems, systemd timers can schedule tasks with second-level precision. Create two unit files:

Service unit

/etc/systemd/system/my-task.service

[Unit]
Description=My 30-second task

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

Timer unit

/etc/systemd/system/my-task.timer

[Unit]
Description=Run my task every 30 seconds

[Timer]
OnBootSec=30s
OnUnitActiveSec=30s
AccuracySec=1s

[Install]
WantedBy=timers.target

Enable and start:

sudo systemctl daemon-reload
sudo systemctl enable --now my-task.timer

OnUnitActiveSec=30s triggers the service 30 seconds after each completion. AccuracySec=1s reduces the default timer coalescing window from 1 minute to 1 second for better precision.

Pros

  • True second-level precision
  • Built-in logging via journalctl
  • Automatic restart on failure
  • No overlap — waits for previous run to finish

Cons

  • More setup than a crontab one-liner
  • Only available on systemd-based distros (not macOS, not Alpine by default)

Method 4: watch Command

The watch utility repeats a command at a set interval:

watch -n 30 /path/to/script.sh

This runs your script every 30 seconds and shows the output in the terminal. To run it in the background without a terminal:

nohup watch -n 30 /path/to/script.sh > /dev/null 2>&1 &

Warning: watch is designed for interactive use. It won't survive reboots unless you wrap it in a systemd service or init script. For production, use Method 3 or Method 5 instead.

Method 5: CronJobPro

CronJobPro supports sub-minute intervals natively. Set the interval to 30 seconds in the dashboard — no sleep tricks, no wrapper scripts, no systemd units. Your task URL or script gets called every 30 seconds with:

  • Built-in monitoring and alerting on failure
  • Automatic overlap protection — skip or queue if the previous run is still going
  • Jitter support to spread load
  • Full execution logs with status codes and response times
  • No server-side setup required

Comparison Table

MethodPrecisionMonitoringSetupOverlap ProtectionProduction-Ready
Sleep trick~1s driftNone1 minManual (flock)Basic
Bash loop~1s driftNone2 minManual (flock)Basic
systemd timer~1sjournalctl5 minBuilt-inYes
watch~1sNone30 secBuilt-in (sequential)No
CronJobPro<1sFull dashboard1 minBuilt-inYes

When You Actually Need Sub-Minute Scheduling

Before setting up a 30-second schedule, consider whether you truly need it. Common legitimate use cases:

  • Health checks — monitoring uptime of critical services
  • Queue processing — polling a job queue for new work
  • Live data feeds — pulling stock prices, sensor data, or metrics
  • Cache warming — refreshing frequently-accessed data
  • Log shipping — forwarding logs to a central system

For many tasks, running every minute is sufficient. If your script takes 2 seconds to run and the data doesn't change faster than once per minute, a 30-second schedule just doubles your server load for no benefit.

Preventing Overlapping Runs

When running tasks every 30 seconds, overlapping runs become a real risk. If your script takes 35 seconds, the next invocation starts before the previous one finishes. This can corrupt data, double-send emails, or overload your database.

Option A: flock (file locking)

* * * * * flock -n /tmp/my-task.lock /path/to/script.sh
* * * * * sleep 30 && flock -n /tmp/my-task.lock /path/to/script.sh

The -n flag makes flock exit immediately (non-blocking) if the lock is already held. The second run simply skips if the first is still going.

Option B: PID file

Add this to the top of your script:

#!/bin/bash
PIDFILE="/tmp/my-task.pid"

if [ -f "$PIDFILE" ] && kill -0 $(cat "$PIDFILE") 2>/dev/null; then
  echo "Already running (PID $(cat "$PIDFILE"))"
  exit 0
fi

echo $$ > "$PIDFILE"
trap "rm -f $PIDFILE" EXIT

# Your actual task here
/path/to/actual-work.sh

FAQ

Can cron run every 10 or 15 seconds?

Not directly. You can extend the sleep trick: for every 15 seconds, use four entries (sleep 0, 15, 30, 45). For every 10 seconds, use six entries. At that point, a systemd timer or CronJobPro is a much cleaner solution.

What about running a cron job every 5 seconds?

You would need 12 crontab entries with the sleep trick, which is impractical and hard to maintain. Use a systemd timer with OnUnitActiveSec=5s, a long-running daemon with a sleep loop, or a managed scheduler like CronJobPro.

Is running a task every 30 seconds bad for server performance?

It depends entirely on the task. A lightweight script (a curl health check, a database query) adds negligible load. A CPU-intensive report or file sync could cause problems, especially if runs overlap. Always benchmark your script's execution time and add overlap protection.

Does cron support sub-second scheduling?

No. Cron's minimum granularity is one minute, and none of these workarounds provide sub-second precision. For sub-second scheduling (every 100ms, every 500ms), you need a custom daemon, event loop, or message queue system like RabbitMQ or Redis Pub/Sub.

Which method is best for production?

For self-hosted infrastructure, systemd timers are the most robust option (built-in logging, dependency management, automatic restart). For managed scheduling with monitoring and alerts, CronJobPro handles sub-minute intervals natively with zero server-side configuration.

Related Articles

Run tasks every 30 seconds — no workarounds needed

CronJobPro supports sub-minute intervals natively. Set your schedule, get monitoring and alerts, and stop wrestling with sleep tricks. Free for up to 5 jobs.