Как запускать cron-задачу каждые 30 секунд
Cron не умеет запускать что-либо чаще раза в минуту: самое мелкое поле строки crontab — минута. Но есть несколько надёжных способов запускать задачу каждые 30, 15 или 10 секунд. Какой подойдёт, зависит от того, сколько длится задача и можно ли двум запускам накладываться.
Две строки crontab со sleep
Самый частый приём: запускать задачу в начале каждой минуты и ещё раз через 30 секунд.
* * * * * /srv/poll.sh * * * * * sleep 30; /srv/poll.sh
Это просто и переживает перезагрузки, как любая задача cron. Второй запуск стартует через 30 секунд после начала минуты, а не через 30 секунд после конца первого, поэтому если poll.sh может идти дольше 30 секунд, одновременно окажутся две копии. Это предотвращает flock:
* * * * * flock -n /tmp/poll.lock /srv/poll.sh * * * * * sleep 30; flock -n /tmp/poll.lock /srv/poll.sh
С -n вторая копия сразу сдаётся, а не ждёт, так что запуски пропускаются, а не копятся в очереди.
Цикл внутри минуты
Для 15 или 10 секунд строк становится слишком много. Используйте цикл:
# каждые 15 секунд
* * * * * for i in 1 2 3 4; do /srv/poll.sh; sleep 15; done
Здесь каждый запуск начинается после окончания предыдущего плюс 15 секунд, так что медленный запуск сдвигает следующие. Если цикл не укладывается в минуту, он накладывается на цикл следующей минуты. Для быстрых задач это нормально, для медленных — повод выбрать другой способ.
Таймер systemd
Таймеры systemd понимают секунды напрямую и никогда не запускают сервис, который ещё работает:
# /etc/systemd/system/poll.timer
[Timer]
OnBootSec=30s
OnUnitActiveSec=30s
AccuracySec=1s
[Install]
WantedBy=timers.target
AccuracySec=1s важен: по умолчанию systemd может задержать срабатывание таймера до минуты ради экономии энергии, и интервал в 30 секунд теряет смысл. Сам сервис — обычный юнит Type=oneshot; полный пример с пингами об успехе и ошибке — в гайде по таймерам systemd.
Постоянно работающий процесс
Если задача запускается каждые несколько секунд, запуск нового процесса каждый раз стоит дороже самой работы. Небольшой цикл, который поддерживает systemd, Docker или Kubernetes, часто чище:
#!/bin/sh while true; do /srv/poll.sh sleep 30 done
Запускайте его с Restart=always в сервисе systemd или с restart: unless-stopped в Docker Compose. Тогда за тем, чтобы он работал, следит супервизор процессов, а не cron.
Что выбрать
| Способ | Подходит для | На что смотреть |
|---|---|---|
| Две строки со sleep | Быстрых задач каждые 30 секунд | Наложения без flock |
| Цикл в одной строке | Быстрых задач каждые 10–20 секунд | Сдвиг и наложения при медленном запуске |
| Таймер systemd | Любого интервала, без наложений | Задайте AccuracySec |
| Постоянный процесс | Запусков каждые несколько секунд | Нужен супервизор, который его перезапустит |
Мониторинг задачи, которая запускается так часто
Задача, которая запускается каждые 30 секунд, громко падает, когда падает, но может и просто остановиться: таймер выключили, процесс умер, сервер пересоздали и забыли восстановить crontab. Пульс ловит всё это. Пинг на каждый запуск не нужен: одного пинга в минуту достаточно, чтобы знать, что задача жива.
В Heartcron создайте проверку с периодом в 1 минуту и коротким запасом времени и отправляйте пинг только из первой строки crontab:
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
Если пинги пропадут больше чем на три минуты, придёт алерт на почту, в Telegram, Slack или Discord. Все сигналы, включая /fail для ошибок, — в документации. Для расписаний от минуты и реже расшифровщик cron-выражений точно покажет, когда сработает строка.