Cron is a powerful time-based job scheduler in Unix-like systems, but it has a fundamental limitation: the smallest time interval it supports is one minute. This becomes problematic when you need to execute tasks more frequently, such as every 30 seconds.
While you could technically create a script that runs every minute and sleeps for 30 seconds between executions, this approach has several drawbacks:
- Process management becomes messy
- Error handling is more complex
- Resource usage is less efficient
Here are three robust approaches to achieve sub-minute scheduling:
1. Using Systemd Timers
Modern Linux distributions with systemd can use timers for more precise scheduling:
# Create a service file
[Unit]
Description=My frequent task
[Service]
ExecStart=/path/to/your/script.sh
# Create a timer file
[Unit]
Description=Run my script every 30 seconds
[Timer]
OnBootSec=30s
OnUnitActiveSec=30s
AccuracySec=1ms
[Install]
WantedBy=timers.target
2. Combining Cron with FIFO
This approach uses cron to trigger a controller script that manages the timing:
#!/bin/bash
# controller.sh
while true; do
/path/to/actual_task.sh
sleep 30
done
Then set up your crontab:
* * * * * /path/to/controller.sh
3. Using a Process Supervisor
Tools like supervisord can manage frequent executions:
[program:my_frequent_task]
command=/path/to/your/script.sh
autostart=true
autorestart=true
startsecs=0
startretries=3
When running tasks this frequently:
- Monitor system resources carefully
- Consider implementing a queue system if tasks might overlap
- Log execution times to identify potential bottlenecks
Here's a complete example of a 30-second monitoring script using systemd:
# monitor.service
[Unit]
Description=Server monitor
[Service]
ExecStart=/usr/local/bin/monitor.sh
# monitor.timer
[Unit]
Description=Run monitor every 30 seconds
[Timer]
OnBootSec=30s
OnUnitActiveSec=30s
[Install]
WantedBy=multi-user.target
Enable it with:
sudo systemctl enable monitor.timer
sudo systemctl start monitor.timer
Traditional cron jobs are fundamentally designed to execute tasks at minute-based intervals. The smallest time unit in standard cron syntax is one minute, represented by the first field in the crontab entry. This limitation stems from cron's original design for system maintenance tasks that typically don't require sub-minute precision.
When you need to run tasks more frequently than every minute, consider these reliable methods:
Method 1: Combining Cron with Script Logic
Create a wrapper script that handles the sub-minute execution internally:
#!/bin/bash
# Script: /usr/local/bin/30sec_job.sh
for i in {1..2}; do
/path/to/actual_script.sh
if [ $i -lt 2 ]; then
sleep 30
fi
done
Then set up your crontab to run this every minute:
* * * * * /usr/local/bin/30sec_job.sh
Method 2: Systemd Timer Units
For modern Linux systems using systemd, create a more precise timer:
# /etc/systemd/system/30sec-job.service
[Unit]
Description=30 Second Job
[Service]
ExecStart=/path/to/your/script.sh
# /etc/systemd/system/30sec-job.timer
[Unit]
Description=Run every 30 seconds
[Timer]
OnBootSec=30
OnUnitActiveSec=30
AccuracySec=1ms
[Install]
WantedBy=timers.target
Enable with:
sudo systemctl enable 30sec-job.timer
sudo systemctl start 30sec-job.timer
When implementing sub-minute cron jobs, be aware of:
- Resource consumption from frequent process spawning
- Potential overlapping executions if jobs run longer than interval
- System load impacts during peak times
Implement robust logging for frequent jobs:
#!/bin/bash
TIMESTAMP=$(date +"%Y-%m-%d %T")
echo "[$TIMESTAMP] Job started" >> /var/log/30sec_job.log
# Your actual job commands here
STATUS=$?
echo "[$(date +"%Y-%m-%d %T")] Job completed with status $STATUS" >> /var/log/30sec_job.log
For Python implementations, consider:
import time
import subprocess
while True:
start_time = time.time()
# Your task logic here
subprocess.run(['/path/to/your/command'])
elapsed = time.time() - start_time
sleep_time = max(0, 30 - elapsed)
time.sleep(sleep_time)