Перейти к содержимому

Heartbeat (push)

Тихий сбой, который никто не замечает: ночное резервное копирование, переставшее запускаться после обновления, cron-задача продления сертификата, потерявшая права, автоматизация Home Assistant, сломавшаяся после переименования. Ничто не жалуется, и вы узнаёте об этом в тот день, когда нужна резервная копия.

Монитор heartbeat (также называемый dead man’s switch, а в Uptime Kuma — push-монитором) переворачивает логику: DumbMonit никого не опрашивает. Задача обращается к секретному URL при каждом запуске, а тревогу поднимает отсутствие обращения.

Каждому монитору heartbeat выдаётся URL вида https://<your DumbMonit>/api/push/<token>. Токен — случайное 128-битное значение, хранящееся в виде хеша для поиска и в зашифрованном виде для отображения: он показывается на странице монитора с кнопкой копирования, пока монитор существует. Он намеренно открыт — ни сессии, ни API-токена, ни заголовка X-Requested-With, — потому что в строке curl в crontab ничего из этого нет. Обладание токеном позволяет лишь сказать «задача выполнилась».

При каждом проходе планировщика (интервал монитора, по умолчанию 60 с) коллектор читает время последнего обращения и записывает:

Ситуацияprobe_successЭффект
Обращений ещё не было(ничего не записывается)Монитор показывает Waiting. Тревоги нет: задача ещё не настроена.
Последнее обращение в пределах ожидаемого интервала + допуск1Reporting.
Последнее обращение старше ожидаемого интервала + допуск0, reason="missed"Down; правило «Heartbeat missed» срабатывает через две минуты.
Последнее обращение сообщило status=down0, reason="reported_down"Down немедленно, что бы ни показывали часы.

Обращение также немедленно переоценивает монитор, так что возобновившаяся задача снимает свою тревогу, не дожидаясь следующего прохода планировщика.

Эндпоинт отвечает 204 с пустым телом, когда обращение записано, 404 — для неизвестного или перегенерированного токена, 400 — для status, который не равен ни up, ни down, и 429 (с Retry-After) при превышении шестидесяти обращений в минуту для одного токена. Принимаются и GET, и POST; HEAD тоже работает.

ПараметрЗначение
statusup (по умолчанию) или down: задача сама сообщает о сбое.
msgПроизвольное слово пояснения, сохраняется (обрезается до 500 символов) и показывается на странице монитора.

Это параметры push-монитора Uptime Kuma: написанный для него скрипт работает без изменений.

Ниже приведены шаги из подсказки рядом с формой.

  1. В адресе напишите короткую метку для задачи («nightly-backup», «certbot-renew»): ничего не опрашивается, метка должна быть лишь уникальной среди ваших heartbeat.

  2. Задайте ожидаемый интервал по расписанию задачи («24h» для ночной, «1h» для ежечасной) и, если расписание плавает, более широкий допуск. Сохраните монитор.

  3. Страница монитора показывает URL для обращения. Добавьте его в конец задачи, чтобы он вызывался только в случае успеха задачи:

    curl -fsS -m 10 --retry 3 https://monit.example.com/api/push/<token>
  4. Задача, умеющая определять, что она завершилась сбоем, может сообщить об этом, а не молчать: добавьте к URL ?status=down&msg=…, и тревога сработает сразу.

  5. Пока не пришло первое обращение, монитор показывает «Waiting», и никаких тревог нет. URL потерян или утёк? «Regenerate» на странице монитора выдаёт новый; старый немедленно перестаёт отвечать.

Учётные данные: нет.

Строка crontab, каждую ночь в 03:00, обращающаяся только при успехе резервного копирования:

0 3 * * * /usr/local/bin/backup.sh && curl -fsS -m 10 --retry 3 https://monit.example.com/api/push/<token> > /dev/null

Скрипт, сообщающий о собственном сбое, с кодом возврата в качестве сообщения:

#!/bin/sh
URL="https://monit.example.com/api/push/<token>"
if /usr/local/bin/backup.sh; then
curl -fsS -m 10 --retry 3 "$URL" > /dev/null
else
curl -fsS -m 10 --retry 3 "$URL?status=down&msg=backup+exit+$?" > /dev/null
fi

Home Assistant, rest_command, вызываемая в конце автоматизации:

rest_command:
dumbmonit_heartbeat:
url: "https://monit.example.com/api/push/<token>"
method: post

Планировщик заданий Windows (PowerShell):

Окно терминала
Invoke-WebRequest -UseBasicParsing -TimeoutSec 10 "https://monit.example.com/api/push/<token>" | Out-Null
КлючНазваниеПо умолчаниюПодсказка
expected_intervalОжидаемый интервал24hКак часто задача должна обращаться: 30m, 1h, 6h, 24h, 7d (или число секунд). Пропуск объявляется, когда этот интервал плюс допуск истёк.
graceДопуск10%Дополнительное время, допускаемое после ожидаемого интервала, прежде чем heartbeat считается пропущенным: процент от интервала (10%) или фиксированная длительность (15m). Никогда не менее одной минуты.

Длительности принимают суффиксы s, m, h, d, w и могут комбинироваться (1h30m); просто число — это число секунд. Ожидаемый интервал должен быть от 10 секунд до года.

Все с меткой probe="push" в дополнение к target, host и tag_*, и все с префиксом dumbmonit_.

МетрикаЗначение
probe_success1, если последнее обращение вовремя и не сообщало о сбое, иначе 0. Отсутствует до первого обращения.
probe_failure_infoНаличие (1) с меткой reason: missed или reported_down.
push_last_seen_secondsВозраст последнего обращения.
push_received_totalОбращений получено с момента создания токена (счётчик).

Доступность за тридцать дней, как для любого монитора службы: avg_over_time(dumbmonit_probe_success{probe="push"}[30d]).

Применяемое встроенное правило: Heartbeat missed (advisory, 2 минуты). Правила «Service down» и «Service flapping» пропускают heartbeat, а «Device unreachable» для них никогда не срабатывает: коллектор работает всегда, меняется только его вердикт.

МаршрутСессияНазначение
GET или POST /api/push/<token>нетСамо обращение. 204, 404, 400 или 429.
GET /api/targets/<id>/pushтребуетсяМонитор: token, path, last_seen_at, last_seen_age_secs, last_status, last_message, received_total, expected_interval_secs, grace_secs, verdict (waiting, on_time, missed, reported_down), settings_error. Создаётся при первом чтении, если отсутствует.
POST /api/targets/<id>/push/regenerateadminНовый токен; предыдущий URL с этого момента отвечает 404. Счётчик и последнее обращение сохраняются.