Cron every 30 seconds
The cron expression * * * * * runs a job every minute; a second line that sleeps 30 seconds first makes it every 30 seconds. The next runs are 2026-10-12 19:17 and 2026-10-12 19:18 UTC. The shortest gap between runs is 30 seconds, so a heartbeat monitor with a 2-minute grace period catches a missed run.
| minute | hour | day of month | month | day of week |
|---|---|---|---|---|
| * | * | * | * | * |
Next runs (UTC)
- Mon 2026-10-12 19:17 UTC (+00:00) · in 8s
- Mon 2026-10-12 19:18 UTC (+00:00) · in 1m
- Mon 2026-10-12 19:19 UTC (+00:00) · in 2m
- Mon 2026-10-12 19:20 UTC (+00:00) · in 3m
- Mon 2026-10-12 19:21 UTC (+00:00) · in 4m
- Mon 2026-10-12 19:22 UTC (+00:00) · in 5m
- Mon 2026-10-12 19:23 UTC (+00:00) · in 6m
- Mon 2026-10-12 19:24 UTC (+00:00) · in 7m
- Mon 2026-10-12 19:25 UTC (+00:00) · in 8m
- Mon 2026-10-12 19:26 UTC (+00:00) · in 9m
Notes for this schedule
sleep 30.OnCalendar=*:*:00/30), but set AccuracySec=1s: the default accuracy is one minute, which would merge the runs.Examples
* * * * * /usr/local/bin/my-job.sh && curl -fsS -m 10 --retry 3 -o /dev/null https://puzaricloud.in/ping/<your-token> * * * * * sleep 30; /usr/local/bin/my-job.sh && curl -fsS -m 10 --retry 3 -o /dev/null https://puzaricloud.in/ping/<your-token>
# /etc/systemd/system/my-job.timer [Unit] Description=Run my-job (every 30 seconds) [Timer] OnCalendar=*-*-* *:*:00/30 AccuracySec=1s Persistent=true [Install] WantedBy=timers.target
# /etc/systemd/system/my-job.service [Unit] Description=my-job [Service] Type=oneshot ExecStart=/usr/local/bin/my-job.sh # runs only if ExecStart succeeded ExecStartPost=/usr/bin/curl -fsS -m 10 --retry 3 -o /dev/null https://puzaricloud.in/ping/<your-token>
Check the calendar spec with systemd-analyze calendar "*-*-* *:*:00/30", then systemctl enable --now my-job.timer. Persistent=true runs a missed job at boot.
apiVersion: batch/v1
kind: CronJob
metadata:
name: my-job
spec:
schedule: "* * * * *"
timeZone: "Etc/UTC" # Kubernetes 1.27+; otherwise the controller's timezone
concurrencyPolicy: Forbid # don't start a new run while one is active
startingDeadlineSeconds: 300 # still start if the controller was briefly down
jobTemplate:
spec:
backoffLimit: 2
template:
spec:
restartPolicy: OnFailure
containers:
- name: job
image: your-image:tag
command: ["/bin/sh", "-c", "/app/run-job.sh && curl -fsS -m 10 --retry 3 -o /dev/null https://puzaricloud.in/ping/<your-token>"]
Common mistakes
timedatectl or date. cronie (RHEL, Fedora, Arch) accepts CRON_TZ=Asia/Kolkata at the top of a crontab; Debian/Ubuntu cron does not.0 0 13 * 5 runs on every 13th and every Friday, not only on Friday the 13th.% is turned into a newline (everything after it goes to the command's stdin). Write date +\%F, not date +%F.PATH (often just /usr/bin:/bin), no login shell and no .bashrc. Use absolute paths and set variables at the top of the crontab.How to get alerted when it doesn't run
A cron job that stops running looks exactly like one that's working: no errors, no output. The reliable fix is a heartbeat (dead man's switch): the job pings a URL each time it finishes, and the monitor alerts you when a ping is late.
- Create a heartbeat in Vigil and choose cron schedule: * * * * *, timezone of your server.
- Set a grace period of about 2 minutes: long enough for a normal run to finish, short enough that you hear about it quickly.
- Add the ping to the end of the command (above). && means only successful runs ping; use /ping/<token>/$? to report the exit code, and /start to catch jobs that hang.
Vigil tells you when a run is missed
Vigil heartbeats understand cron expressions and timezones, so they know exactly when each run is due. Missed, failed or stuck runs alert you on email, Slack, Telegram, Discord or a webhook, and the history shows every run's duration.