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.shHow 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
doneThen add a single crontab entry:
* * * * * /path/to/run-every-30s.shThe & 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.shTimer 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.targetEnable and start:
sudo systemctl daemon-reload
sudo systemctl enable --now my-task.timerOnUnitActiveSec=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.shThis 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
| Method | Precision | Monitoring | Setup | Overlap Protection | Production-Ready |
|---|---|---|---|---|---|
| Sleep trick | ~1s drift | None | 1 min | Manual (flock) | Basic |
| Bash loop | ~1s drift | None | 2 min | Manual (flock) | Basic |
| systemd timer | ~1s | journalctl | 5 min | Built-in | Yes |
| watch | ~1s | None | 30 sec | Built-in (sequential) | No |
| CronJobPro | <1s | Full dashboard | 1 min | Built-in | Yes |
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.shThe -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.shFAQ
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
Feature comparison, syntax differences, and when to choose each.
Cron Job Not Running? 12 Common CausesDiagnose and fix cron jobs that are not executing as expected.
Cron Expression CheatsheetQuick-reference guide to cron syntax with copy-paste examples.
Cron Expression GeneratorBuild any cron schedule visually, with instant human-readable preview.
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.