Heartbeat-мониторинг — это reverse-мониторинг (или dead-man's-switch): ваша cron-задача или фоновый процесс сама отправляет ping на наш сервер после успешного выполнения, и если ping не пришёл вовремя — Tracker.ru присылает алерт. Это противоположность обычному URL-мониторингу: там Tracker.ru опрашивает ваш сайт по pull-модели; здесь — push-модель, ваш сервис уведомляет нас сам.
Главное отличие от URL-мониторинга: heartbeat работает для задач, у которых нет публичного эндпоинта. Бэкап в три часа ночи, выгрузка в S3, ETL-пайплайн, очередь обработки — снаружи их не «опросить». Heartbeat закрывает этот класс задач.
Создание монитора
Откройте /my/heartbeat в личном кабинете, нажмите «Создать монитор». Заполните:
- Имя — для удобства поиска в списке (например,
nightly-backup-prod). - Период (period) — как часто ваша задача должна слать ping. Минимум зависит от тарифа: Free — 5 минут (300 секунд), Basic — 1 минута (60 секунд), Pro — 1 минута (60 секунд). Реалистичные значения для cron — от 5 минут до 24 часов.
- Grace — дополнительное время сверх period, в течение которого пропуск ping ещё не считается алертом. Полезно при нестабильной сети или джобе с переменной длительностью.
- Alert after misses — сколько подряд пропусков должно случиться, прежде чем монитор переключится в
downи пришлёт уведомление. 1 — алерт после первого же пропуска (агрессивно), 2–3 — защита от ложных срабатываний. - Каналы уведомлений — Telegram, MAX, Email, Webhook. Подтягиваются из общих настроек профиля.
После сохранения Tracker.ru сгенерирует уникальный 32-символьный hex-токен и покажет URL для ping.
Endpoint и формат запроса
Endpoint: GET https://hb.tracker.ru/ping/{token} (или POST для CI/CD-сценариев с body). Token — 32 символа hex (^[0-9a-f]{32}$).
# GET — самый простой вариант
curl -fsSL https://hb.tracker.ru/ping/<token>
# POST — для сценариев с body (опциональное message в form)
curl -fsSL -X POST -d 'message=backup-2026-05-01.sql.gz' \
https://hb.tracker.ru/ping/<token>
Опциональное сообщение ?msg=. К ping можно прицепить короткое текстовое сообщение через query-параметр ?msg=... (для GET) или message=... в POST-form/body. Лимит — 64 символа (это руны Unicode, а не байты — для кириллицы это до 128 байт UTF-8). Сообщение попадает в last_ping_message монитора и видно в /my/heartbeat/{id}. Удобно класть туда имя бэкап-файла, hostname сервера, exit-code или длительность джоба.
# С сообщением — backup-имя файла
curl -fsSL "https://hb.tracker.ru/ping/<token>?msg=backup-$(date +%F).sql.gz"
Sanitization. Tracker.ru автоматически удаляет из сообщения управляющие символы, null bytes и unicode overrides — это защита от инъекций в Telegram-уведомлениях. HTML escape применяется при выводе, поэтому <script> не сломает рендер.
Rate limit. 30 запросов в минуту на один токен. Если ваш скрипт зациклится и начнёт слать ping каждые 100 миллисекунд, лишние запросы будут возвращать 429 Too Many Requests — но монитор всё равно засчитает первый ping в окне.
Возможные ответы:
200 OK—{"ok":true}. Ping принят, монитор обновлён.401 Unauthorized— включён режимtoken_and_secret, но headerX-Heartbeat-Secretне отправлен или неверный.404 Not Found— токен не найден (неверный или удалённый монитор).429 Too Many Requests— превышен rate limit.
Готовые интеграции
Bash + cron
Самый частый сценарий — ночной бэкап или периодический отчёт через crontab -e. Конструкция && curl шлёт ping только при успешном завершении основной команды (exit code 0):
0 3 * * * /usr/local/bin/backup.sh && curl -fsSL https://hb.tracker.ru/ping/<token>
Флаги curl: -f отключает HTTP-ошибки в stdout, -s глушит прогресс-бар, -S оставляет ошибки на stderr, -L следует редиректам. Если cron-демон шлёт stderr на почту, лишних писем от curl не будет.
С логированием результата ping в файл:
0 3 * * * /usr/local/bin/backup.sh && curl -fsSL https://hb.tracker.ru/ping/<token> >> /var/log/backup-ping.log 2>&1
Systemd timer
Для современных Linux-серверов systemd timer часто заменяет cron. Ping добавляется через ExecStartPost в .service-юнит:
# /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
ExecStartPost=/usr/bin/curl -fsSL https://hb.tracker.ru/ping/<token>
# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup nightly
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
ExecStartPost выполняется только если ExecStart вернул exit code 0 — при падении основной команды ping не уйдёт. Логи доступны через journalctl -u backup.service.
GitHub Actions
Для scheduled-workflow токен кладётся в secrets.TRACKER_PING_TOKEN, ping добавляется как последний step. Если предыдущие steps упали, по умолчанию следующие skip'ятся — ping не уйдёт, и Tracker.ru засчитает пропуск:
name: Nightly backup
on:
schedule:
- cron: '0 3 * * *'
jobs:
backup:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run backup
run: ./scripts/backup.sh
- name: Heartbeat ping
run: curl -fsSL https://hb.tracker.ru/ping/${{ secrets.TRACKER_PING_TOKEN }}
Если важно слать ping строго при успехе предыдущего step — добавьте if: success() (это поведение по умолчанию). Не используйте if: always() — это сломает heartbeat (ping будет слаться даже при падении задачи).
Supervisord
Для долгоживущих процессов под supervisord используется eventlistener с подпиской на PROCESS_STATE_RUNNING или периодический at-таск. Простейший вариант — отдельная supervisor-программа с autorestart=false, которая шлёт ping раз в час и завершается:
[program:tracker-heartbeat]
command=/bin/sh -c 'while true; do curl -fsSL https://hb.tracker.ru/ping/<token>; sleep 3600; done'
autostart=true
autorestart=true
user=appuser
stderr_logfile=/var/log/supervisor/tracker-heartbeat.err.log
Это даёт «I'm alive» сигнал самого supervisord. Для конкретных воркеров (Sidekiq, Celery) лучше слать ping из самого джоба после успешной обработки задачи — так монитор привязан к функциональности, а не к процессу.
Поля и параметры монитора
| Поле | Описание |
|---|---|
type |
reverse (cron шлёт ping), worker (фоновый воркер), agent (системный агент) |
status |
new (только что создан), up (работает), down (пропустил ping), paused |
period |
Ожидаемый интервал между ping в секундах. Минимум: Free 300, Basic/Pro 60. |
grace |
Доп. время сверх period до признания пропуска. В секундах. |
alert_after_misses |
Сколько подряд пропусков до алерта. 1 — агрессивно, 2–3 — защита от флапов. |
notify_telegram |
bool — слать в Telegram |
notify_email |
bool — слать на email |
notify_max |
bool — слать в MAX-мессенджер |
reminder_interval |
Интервал повторных напоминаний пока монитор в down. 0 — без напоминаний. |
auth_mode |
token_only (по умолчанию) или token_and_secret (двухфакторка) |
secret |
32-символьный hex secret для token_and_secret. Хранится в БД, не показывается повторно. |
last_ping_message |
Последнее сообщение из ?msg= (max 64 символа рун Unicode). |
Двухфакторная защита (X-Heartbeat-Secret)
По умолчанию все мониторы создаются в режиме token_only — 32-символьного hex-токена достаточно для большинства сценариев. Перебор такого токена практически невозможен, и даже если третья сторона его узнает, единственное что она сможет — отправить лишний ping (что не вредит).
Двухфакторка нужна, если:
- токен попадает в публичные репозитории (например, в
README.mdили примере конфига); - ping триггерит side-effect в вашей инфраструктуре, и вы хотите гарантированно подтвердить отправителя;
- compliance-требования вашего проекта требуют второй фактор.
Включение. В настройках монитора переключите auth_mode на token_and_secret. Tracker.ru сгенерирует 32-символьный secret — сохраните его сразу, повторно показан не будет.
curl -fsSL \
-H 'X-Heartbeat-Secret: <secret>' \
https://hb.tracker.ru/ping/<token>
Сравнение secret на стороне Go-воркера — constant-time (subtle.ConstantTimeCompare), что защищает от тайминговых атак. При неверном или отсутствующем header endpoint вернёт 401 Unauthorized, ping не засчитается.
Опциональное сообщение ?msg=
Сообщение в ping видно в /my/heartbeat/{id} в поле «Последнее сообщение», и попадает в текст уведомления в Telegram/MAX/Email при следующем падении. Полезные сценарии:
- Имя бэкап-файла:
?msg=backup-prod-2026-05-01.sql.gz— видно, что именно сохранилось. - Exit-code:
?msg=ok-exit-0или?msg=warn-exit-1— статус последнего запуска. - Hostname:
?msg=backup-host-01— какая нода прислала ping в multi-host setup. - Длительность:
?msg=took-42s— performance-метрика для отслеживания деградации.
Лимит — 64 символа рун Unicode (для кириллицы это до 128 байт UTF-8). Что не помещается, обрезается без ошибки.
Уведомления при пропуске
Когда за period + grace (с учётом alert_after_misses) ping не пришёл, монитор переключается в down и в выбранные каналы отправляется уведомление:
🚨Heartbeat пропустил ping: nightly-backup-prod
Период: 1 час, grace: 10 минут
Последний ping: 2026-05-01 02:15:09 (msg: backup-prod-2026-04-30.sql.gz)
При следующем успешном ping монитор переходит в up:
✅Heartbeat восстановлен: nightly-backup-prod
Был в down: 2 ч 15 мин
Если включён reminder_interval, повторные напоминания о пропуске отправляются с указанным интервалом пока монитор в down.
Лимиты и тарификация
- Бесплатно на всех тарифах. Heartbeat — часть подписки, отдельной платы нет.
- Количество мониторов: Free — 1, Basic — 5, Pro — 20. Это лимит одновременно активных мониторов.
- Минимальный period: Free — 5 минут (300 секунд), Basic — 1 минута (60 секунд), Pro — 1 минута (60 секунд). Источник: тарифная матрица в БД.
- Rate limit: 30 запросов в минуту на один токен. Защита от лупа в скрипте.
- Max длина
?msg=: 64 символа (рун Unicode, не байт).
Troubleshooting
Ping вернул 404 Not Found. Токен неверный или монитор удалён. Проверьте URL в /my/heartbeat/{id} — он показывается в карточке монитора.
Ping вернул 401 Unauthorized. Включён режим token_and_secret, но header X-Heartbeat-Secret не отправлен или неверный. Проверьте: header передаётся именно в HTTP-запросе (не в query-параметре), значение совпадает с тем, что показано при создании secret. Если потеряли secret — пересоздайте через настройки монитора.
Ping вернул 429 Too Many Requests. Превышен лимит 30 req/min/token. Скорее всего ваш скрипт зациклился и шлёт ping в хот-лупе. Первый ping в окне всё равно засчитан, монитор обновлён — но архитектурно проблему стоит починить.
Монитор всё ещё down после успешного ping. Возможно, фоновое обновление кеша. Подождите 1 минуту и обновите страницу /my/heartbeat/{id}. Если статус не сменился — посмотрите журнал ping-событий: возможно, ping вернул не 200, а 429 (rate limit) или 401 (secret mismatch), и реальное обновление не произошло.
Алерт пришёл, хотя задача отработала. Чаще всего — period слишком короткий относительно реальной длительности джоба. Увеличьте grace или поставьте alert_after_misses=2 для защиты от единичного пропуска.
Связанные
- /features/heartbeat-monitoring — общий обзор heartbeat-мониторинга и сравнение с фокусными cron-сервисами.
- /docs/notifications/telegram — настройка Telegram-уведомлений.
- /docs/notifications/email — email-уведомления.
- /docs/notifications/webhooks — Webhook с подписью HMAC-SHA256.
- /docs/api — Laravel API-эндпоинты
/api/heartbeats/*для CRUD-управления мониторами.