MAATRIX / Блог / Healthchecks.io: мониторинг cron-задач

Healthchecks.io: мониторинг cron-задач

Healthchecks.io: мониторинг cron-задач

MAATRIX

У вас наверняка есть cron-задача, за которой никто не следит. Бэкап базы, ночная рассылка, синхронизация файлов — она отработала вчера, неделю назад, а сегодня упала с ошибкой прав доступа или зависла на середине, и никто об этом не узнал. Обычный мониторинг тут бессилен: он проверяет, что сервис отвечает на запрос, а не то, что задача, которая должна была отработать в 3:00 ночи, реально завершилась. Healthchecks.io закрывает этот пробел — одной строчкой в конце cron-команды.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Проблема «мёртвого человека» в мониторинге

В промышленной автоматике есть понятие dead man's switch — «выключатель мертвеца». Если оператор перестаёт нажимать на педаль, система считает, что с ним что-то случилось, и останавливает состав. Система не ждёт сигнала о поломке, она ждёт регулярного подтверждения, что всё в порядке, и тревогу поднимает именно при отсутствии этого подтверждения.

Классический мониторинг вроде Zabbix, Prometheus или Uptime Kuma работает в обратную сторону: он сам стучится к сервису и проверяет ответ. Это отлично ловит упавший веб-сервер или недоступный порт, но не подходит для одноразовых фоновых задач. Cron-скрипт для бэкапа не слушает порт, у него нет HTTP-эндпоинта, который можно опросить. Он либо выполнился, либо нет — и узнать об этом можно, только если сама задача об этом сообщит.

Типичный сценарий из практики: скрипт бэкапа PostgreSQL перестаёт работать после обновления пакетов на сервере (поменялся путь к pg_dump), exit-код cron никто не проверяет, письмо от MTA улетает в спам или вовсе не настроено — и через три недели выясняется, что бэкапов нет вообще, в момент, когда они внезапно понадобились. Healthchecks.io делает эту ситуацию видной сразу, а не постфактум.

Как это работает: пинг вместо опроса

Идея Healthchecks.io зеркальна обычному мониторингу. Вы создаёте в сервисе «проверку» (check) — она получает уникальный URL вида https://hc-ping.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. Задача на сервере после успешного завершения должна сама сходить по этому URL простым curl. Это и есть «нажатие на педаль».

Сервис хранит ожидаемый период (например, «раз в сутки») и допустимое опоздание (grace period, например, 30 минут). Пока пинги приходят вовремя — проверка зелёная, никто ничего не получает, это нормальное, «скучное» состояние мониторинга. Как только пинг не пришёл в ожидаемое окно — статус переключается в «просрочено», и Healthchecks.io отправляет уведомление по всем настроенным каналам.

Отличие от обычного uptime-мониторинга: здесь проверяется не доступность сервиса, а факт успешного завершения конкретного действия. Можно отдельно пинговать начало и конец задачи, чтобы видеть в дашборде реальную длительность выполнения и ловить ситуации, когда скрипт не упал, а просто завис.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать VPS

Быстрый старт: первая проверка за 5 минут

Регистрация на healthchecks.io бесплатна для небольшого числа проверок (на момент публикации бесплатный план допускает 20 проверок — учитывайте, что условия тарифов сервис может менять, сверяйтесь с актуальной страницей цен). Дальше всё делается в несколько шагов.

  1. В панели нажимаете Add Check, даёте проверке понятное имя, например backup-postgres-daily.
  2. Сервис сразу выдаёт Ping URL — именно его нужно вставить в конец вашей команды или скрипта.
  3. Задаёте период (Schedule) — как часто задача должна отчитываться, и Grace Time — на сколько минут/часов допустимо опоздание, прежде чем поднимется тревога.

Дальше берёте существующую cron-задачу и просто дописываете к ней вызов curl через &&:

# было
0 3 * * * /usr/local/bin/backup-postgres.sh

# стало
0 3 * * * /usr/local/bin/backup-postgres.sh && curl -fsS -m 10 --retry 5 https://hc-ping.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx > /dev/null

Логика && здесь ключевая: если backup-postgres.sh завершится с ошибкой (ненулевой exit-код), curl вообще не выполнится, пинг не уйдёт — и Healthchecks.io через grace period поднимет тревогу. Если скрипт просто зависнет и не завершится — пинг тоже не уйдёт вовремя, сработает та же тревога. Именно это и решает задачу «мёртвого man's switch»: неважно, упал скрипт с ошибкой, завис или сервер вообще выключился — молчание одинаково детектируется.

Флаги curl тут не случайны: -fsS подавляет прогресс-бар, но показывает ошибку, если она есть, -m 10 ограничивает таймаут запроса 10 секундами, чтобы зависший ping не держал cron-джобу вечно, --retry 5 переживает кратковременные сетевые сбои до самого Healthchecks.io.

Базовый вариант выше ловит только факт «пинг не пришёл вовремя», но не различает, где именно проблема — в самой задаче или в её длительности. Для более точной диагностики Healthchecks.io поддерживает дополнительные суффиксы к Ping URL:

# сигнал начала выполнения (для замера длительности)
curl -fsS -m 10 https://hc-ping.com/xxxxxxxx.../start

# основной скрипт
/usr/local/bin/backup-postgres.sh
EXIT_CODE=$?

# явный сигнал успеха или ошибки с кодом
if [ $EXIT_CODE -eq 0 ]; then
  curl -fsS -m 10 https://hc-ping.com/xxxxxxxx...
else
  curl -fsS -m 10 --data-raw "backup failed, exit code $EXIT_CODE" https://hc-ping.com/xxxxxxxx.../fail
fi

Суффикс /start фиксирует момент запуска — по разнице между /start и финальным пингом в дашборде видна реальная длительность выполнения, и можно отдельно настроить тревогу, если задача выполняется аномально долго. Суффикс /fail принудительно переводит проверку в состояние ошибки независимо от расписания — удобно, когда скрипт сам понимает, что что-то пошло не так. Тело запроса (--data-raw) сохраняется в логе последних пингов и помогает быстро понять причину, не заходя на сервер.

Уведомления: email, Telegram, Slack, вебхуки

Просроченная проверка бесполезна, если о ней никто не узнает — уведомления настраиваются в разделе Integrations и привязываются к конкретным проверкам или группам.

КаналОсобенности
EmailРаботает из коробки без настройки, подходит как базовый канал
TelegramЧерез официального бота @healthchecks_io, alert приходит в личку или в группу за секунды
SlackЧерез Incoming Webhook, удобно для команды с общим каналом инцидентов
WebhookПроизвольный HTTP-запрос — можно завести в свою систему алертинга, PagerDuty, Opsgenie
SMS / телефонный звонокЕсть на платных планах, для критичных задач вроде продовых бэкапов

Для Telegram процесс подключения простой: находите бота @healthchecks_io, отправляете /start, получаете код, вставляете его в интеграцию на сайте — готово, дальше в разделе проверки достаточно включить галочку у нужного канала. Если у вас уже настроены алерты в Telegram на сервере для других целей, логично завести отдельную группу под пропущенные cron-задачи, чтобы не смешивать сигналы разной срочности.

Отдельно стоит настроить не только уведомление «проверка просрочена», но и «проверка снова в порядке» (Up notification) — иначе легко забыть, что проблема ещё не решена, если тревога один раз промелькнула и потерялась в чате.

Self-hosted вариант: свой Healthchecks.io на VPS

Healthchecks.io — открытый исходный код (Django-приложение), и его можно поднять на собственном сервере, если не хочется зависеть от внешнего сервиса или нужен полный контроль над данными. Официальный образ поддерживает запуск через Docker Compose.

Минимальный docker-compose.yml для self-hosted инсталляции:

services:
  healthchecks:
    image: healthchecks/healthchecks:latest
    restart: unless-stopped
    ports:
      - "8000:8000"
    environment:
      SECRET_KEY: "замените-на-случайную-строку"
      ALLOWED_HOSTS: "monitor.example.com,localhost"
      SITE_ROOT: "https://monitor.example.com"
      DEFAULT_FROM_EMAIL: "healthchecks@example.com"
      DB: "sqlite"
    volumes:
      - hc_data:/data

volumes:
  hc_data:

Для продакшена вместо DB: sqlite разумнее подключить отдельный контейнер PostgreSQL — SQLite подойдёт только для личного использования с небольшим числом проверок. После первого запуска нужно создать суперпользователя и, если нужны email-уведомления, настроить SMTP-переменные (EMAIL_HOST, EMAIL_PORT, EMAIL_HOST_USER) — без них система работает, но письма слать не сможет, останутся Telegram/Slack/webhook.

Перед контейнером нужен обратный прокси с HTTPS — например, Nginx как reverse-proxy с сертификатом Let's Encrypt, потому что Ping URL и панель с паролями должны ходить только по защищённому соединению.

Плюс self-hosted варианта — данные и Ping URL не покидают вашу инфраструктуру, и лимита на число проверок нет. Минус — вы сами отвечаете за доступность мониторящего сервиса: если упадёт сервер с вашим Healthchecks.io, некому прислать алерт о том, что он упал. Разумный компромисс — держать инсталляцию на отдельном небольшом VPS, физически не связанном с основными серверами, чьи задачи он мониторит.

Практические сценарии: что стоит подключить в первую очередь

Не обязательно оборачивать в Healthchecks.io вообще все cron-задачи — начните с тех, где тихий отказ дороже всего обходится.

  • Резервное копирование БД. Если вы уже настроили бэкап MySQL по расписанию, одна строчка с curl — минимальная страховка от ситуации «бэкапы не делались три месяца».
  • Рассылки и email-кампании. Важно знать не только что скрипт запустился, но и что письма реально отправлены, а не упали на первом же адресе из-за смены пароля SMTP.
  • Синхронизация файлов и репликация. rsync между серверами или синхронизация с облачным хранилищем — тихий сбой здесь долго остаётся незамеченным, пока не понадобятся «свежие» данные, которых на самом деле нет.
  • Ротация логов и очистка временных файлов. Не критично для бизнеса, но накопление логов способно занять всё место на диске — дешевле поймать остановившуюся очистку заранее.
  • Обновление сертификатов и security-патчей. Сбой обнаруживается не сразу, а в момент, когда сертификат уже просрочен.

Здравый подход — начать с двух-трёх самых критичных задач, убедиться, что уведомления реально доходят (искусственно вызвать сбой), и постепенно расширять список.

Ограничения и на что обратить внимание

Healthchecks.io — простой инструмент с разумными границами применимости. Он не заменяет полноценный мониторинг ресурсов сервера — для CPU, памяти, диска нужны такие инструменты, как Zabbix или связка Grafana и Prometheus. Он решает узкую задачу — подтверждение факта выполнения по расписанию, и не пытается быть универсальной системой наблюдаемости.

Сервис зависит от исходящего интернет-соединения с сервера. Если внешний доступ пропал (проблемы с сетью, блокировка фаерволом), пинг не дойдёт — и это тоже засчитается как «задача не выполнена», хотя сама задача могла отработать штатно.

Наконец, механизм подтверждения наивный: если скрипт успешно выполнил curl, но перед этим тихо пропустил часть своей работы (например, забэкапил не все таблицы из-за изменившейся схемы), Healthchecks.io этого не увидит — он проверяет факт вызова, а не корректность результата. Для критичных данных стоит дополнительно проверять целостность бэкапов отдельным способом.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать VPS

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Нужно ли открывать входящий порт на сервере для работы Healthchecks.io?

Нет, если вы используете облачный сервис — сервер сам инициирует исходящее соединение, входящие порты открывать не нужно. Для self-hosted варианта, наоборот, нужен открытый входящий порт (обычно через reverse-proxy на 443), чтобы cron-задачи с других серверов могли достучаться.

Что если сервер целиком выключился и cron вообще не запустился?

Именно этот случай Healthchecks.io ловит лучше всего: пинг не пришёл вовремя по любой причине — сбой скрипта, зависание, выключенный сервер, отсутствие сети, — проверка помечается просроченной, уходит алерт. Причину сбоя дальше смотрите уже на самом сервере.

Можно ли мониторить задачи, которые запускаются не по cron, а через systemd timers?

Да, механизм тот же — curl к Ping URL добавляется в саму команду, планировщик (cron, systemd timer, Kubernetes CronJob) для Healthchecks.io не важен.

Что произойдёт с self-hosted вариантом при большом числе проверок?

Ограничений нет — упираться вы будете только в ресурсы собственного VPS, что при десятках и даже сотнях проверок с редким периодом не требует ничего мощного.

Стоит ли использовать Healthchecks.io вместе с Uptime Kuma?

Да, это взаимодополняющие инструменты: Uptime Kuma проверяет доступность сервисов снаружи, а Healthchecks.io — что фоновые задачи внутри сервера реально отработали.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →