Подключение за две минуты
Всё, что нужно для интеграции: один HTTP-запрос из вашего скрипта. Никаких агентов, доступа по SSH и настройки firewall.
01 Как это работает #
OpsPulse работает по принципу «мёртвого выключателя» (dead man’s switch). Вместо того чтобы стучаться к вам на сервер, мы ждём сигнал от вашей задачи. Вы создаёте проверку, получаете персональный Ping URL и вызываете его после успешного завершения скрипта.
Если пинг не пришёл в ожидаемое окно — задача упала, зависла, сервер выключен или cron вообще не запустился. Мы отправляем алерт.
Мы принимаем GET, POST и HEAD. Тело запроса игнорируется — важен сам факт вызова.
02 Ping URL #
Адрес проверки выглядит так — UUID выдаётся при создании и не меняется:
Кто угодно, зная адрес, может отправить пинг и «замаскировать» реальный сбой. Не публикуйте его в открытых репозиториях. Храните в переменных окружения или в .env.
Удобный вариант — вынести адрес в переменную:
# подключается в скрипте: source /etc/opspulse.env PING_BACKUP=https://opspulse.ru/ping/550e8400-e29b-41d4-a716-446655440000
03 Лимиты и таймауты #
У каждой проверки два независимых параметра: период — как часто вы обещаете присылать пинг, и grace-период — сколько мы ждём сверху, прежде чем поднять тревогу.
| Параметр | Значение | Комментарий |
|---|---|---|
| Минимальный период | 10 мин / 1 мин | 10 минут на тарифе START, от 1 минуты на PRO и PREMIUM. |
| Максимальный период | 365 дней | Подходит для редких задач: ротация сертификатов, годовые отчёты. |
| Grace-период | 5 мин | Значение по умолчанию, меняется в настройках проверки. Ставьте с запасом на «долгие» дни. |
| Rate limit | 1 / сек | Чаще пинговать бессмысленно — лишние запросы отбрасываются с 429. |
| Повторное напоминание | 30 мин | PRO и PREMIUM: если проверка не восстановилась, придёт напоминание. |
Возьмите обычную длительность задачи и умножьте на два. Бэкап на 20 минут → grace 40 минут. Слишком маленький grace даёт ложные алерты, слишком большой — задерживает реальные.
04 Коды ответов #
| Код | Значение | Что делать |
|---|---|---|
| 200 | Пинг принят, таймер сброшен. | Ничего. |
| 404 | Проверка с таким UUID не найдена. | Сверьте UUID: возможно, проверка удалена или адрес скопирован не полностью. |
| 429 | Слишком часто. | Уменьшите частоту вызовов — таймер уже сброшен предыдущим пингом. |
| 5xx | Проблема на нашей стороне. | Флаг --retry в curl повторит запрос. Ваш скрипт не пострадает. |
05 Crontab #
Самый частый сценарий — мониторинг бэкапов. Оператор && гарантирует,
что пинг уйдёт только при успешном завершении команды: если backup.sh
вернёт ненулевой код, вторая часть строки не выполнится и вы получите алерт.
Базовый пример
# бэкап в 03:00. Успех → пинг 0 3 * * * /home/user/backup.sh && \ curl -fsS -m 10 --retry 5 https://opspulse.ru/ping/UUID
Что означают флаги curl
-f— считать ошибкой ответ 4xx/5xx, а не «успех с текстом ошибки».-s -S— тихий режим, но ошибки всё же показать. Без этого cron будет присылать вам письма с прогресс-баром.-m 10— общий таймаут 10 секунд, чтобы запрос не подвесил cron-задачу.--retry 5— повторить, если сеть мигнула.
Если важно ловить и падения тоже
Вариант выше молчит при ошибке, и алерт придёт по таймауту. Если хотите узнать о падении сразу, а не через grace-период, отправляйте разный сигнал:
0 3 * * * /home/user/backup.sh \ && curl -fsS -m 10 $PING_BACKUP \ || curl -fsS -m 10 $PING_BACKUP/fail
В crontab % — специальный символ, его нужно экранировать как \%. Это ломает команды с date +%Y чаще, чем кажется.
06 systemd #
Для юнитов с Type=oneshot используйте ExecStartPost — он выполнится
только если основная команда завершилась успешно.
[Unit] Description=My Important Task [Service] Type=oneshot ExecStart=/usr/bin/python3 /opt/app/my_script.py # пинг только при успешном ExecStart ExecStartPost=/usr/bin/curl -fsS -m 10 https://opspulse.ru/ping/UUID
Если задача запускается таймером, помните: мониторить нужно период таймера, а не сам факт наличия юнита.
[Timer] OnCalendar=daily Persistent=true # в OpsPulse: период 24 ч, grace с запасом
07 Bash-скрипты #
Ключевая строка — set -euo pipefail. Без неё скрипт продолжит работу
после ошибки и дойдёт до пинга, отрапортовав об успехе, которого не было.
#!/usr/bin/env bash # -e: выход при ошибке | -u: ошибка на пустой переменной # -o pipefail: ошибка в любом звене пайпа set -euo pipefail PING="https://opspulse.ru/ping/UUID" echo "Starting backup…" tar -czf /backup/site.tar.gz /var/www/html aws s3 cp /backup/site.tar.gz s3://my-bucket/ # дошли до этой строки — значит ошибок не было curl -fsS -m 10 "$PING"
Пинг при любом выходе через trap
Если нужно сообщать и об успехе, и об ошибке — повесьте обработчик на EXIT.
Так пинг уйдёт, даже если скрипт упал в середине.
#!/usr/bin/env bash set -euo pipefail PING="https://opspulse.ru/ping/UUID" report() { local code=$? if [ "$code" -eq 0 ]; then curl -fsS -m 10 "$PING" || true else echo "failed with $code" >&2 fi } trap report EXIT # … основная работа … /opt/app/do_work.sh
|| true
Чтобы недоступность OpsPulse не уронила ваш скрипт и не изменила его код выхода. Мониторинг не должен ломать то, что мониторит.
08 Мониторинг диска #
Приём, который выходит за рамки cron: скрипт присылает пинг, только пока условие выполняется. Место закончилось → пинги прекратились → пришёл алерт.
#!/usr/bin/env bash set -uo pipefail THRESHOLD=90 PING="https://opspulse.ru/ping/UUID" # процент занятого места на / USED=$(df --output=pcent / | tr -dc '0-9') if [ "$USED" -lt "$THRESHOLD" ]; then # места хватает → пингуем curl -fsS -m 10 "$PING" else # места мало → молчим, OpsPulse поднимет тревогу echo "Disk usage ${USED}% >= ${THRESHOLD}%" >&2 fi
Запускайте каждые 10 минут, в настройках проверки поставьте период 10 минут и grace 5 минут. Тем же способом можно следить за длиной очереди, свежестью файла бэкапа или числом процессов.
09 Docker #
Указать Ping URL как healthcheck.test напрямую. Тогда контейнер проверяет доступность OpsPulse, а не собственную работоспособность: приложение может лежать, а healthcheck — быть зелёным.
Правильно — сначала проверить своё приложение, и только потом пинговать:
services:
app:
image: my-app
healthcheck:
test: ["CMD-SHELL",
"curl -fsS localhost:8000/health && curl -fsS -m 10 $PING_URL"]
interval: 1m
timeout: 10s
retries: 3
environment:
PING_URL: https://opspulse.ru/ping/UUID
Разовая задача в контейнере
# дамп БД из контейнера, пинг при успехе 0 4 * * * docker compose exec -T db pg_dump -U app app > /backup/db.sql \ && curl -fsS -m 10 https://opspulse.ru/ping/UUID
10 Python #
Оберните пинг в try: сбой отправки не должен ломать саму задачу.
import os, logging import requests PING_URL = os.environ["PING_URL"] log = logging.getLogger("task") def ping(): """Пинг не должен ронять задачу.""" try: requests.get(PING_URL, timeout=10).raise_for_status() except requests.RequestException as e: log.warning("ping failed: %s", e) def main(): do_heavy_work() # упадёт → пинга не будет → придёт алерт ping() if __name__ == "__main__": main()
Celery periodic task
from celery import shared_task @shared_task def nightly_report(): build_report() ping() # только после успешной сборки
11 PHP #
file_get_contents() без таймаута может подвесить скрипт, а при ошибке
бросит warning. Задайте контекст:
<?php // … ваша логика; при ошибке — throw / exit function opsPing(string $url): void { $ctx = stream_context_create([ 'http' => ['timeout' => 10, 'ignore_errors' => true], ]); @file_get_contents($url, false, $ctx); } opsPing('https://opspulse.ru/ping/UUID');
Если в проекте есть cURL — надёжнее так:
$ch = curl_init('https://opspulse.ru/ping/UUID'); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10, ]); curl_exec($ch); curl_close($ch);
12 Node.js #
Начиная с Node 18 хватит встроенного fetch без зависимостей.
const PING_URL = process.env.PING_URL; async function ping() { try { await fetch(PING_URL, { signal: AbortSignal.timeout(10_000), }); } catch (e) { console.warn('ping failed:', e.message); } } try { await doHeavyWork(); await ping(); } catch (e) { console.error(e); process.exit(1); // пинга нет → будет алерт }
13 Go #
package main import ( "log" "net/http" "os" "time" ) func ping() { c := &http.Client{Timeout: 10 * time.Second} resp, err := c.Get(os.Getenv("PING_URL")) if err != nil { log.Printf("ping failed: %v", err) return } resp.Body.Close() } func main() { if err := doWork(); err != nil { log.Fatal(err) // пинга нет → алерт } ping() }
14 Slack #
Создайте incoming webhook и вставьте его в настройках канала уведомлений в OpsPulse.
- Откройте api.slack.com/apps и нажмите Create New App.
- Выберите From scratch, введите имя (например, OpsPulse) и укажите workspace.
- В меню слева — Incoming Webhooks, переведите тумблер в On.
- Нажмите Add New Webhook to Workspace и выберите канал.
- Скопируйте Webhook URL (вида
https://hooks.slack.com/…) и вставьте в OpsPulse.
15 Discord #
- Настройки сервера → Integrations.
- Webhooks → New Webhook.
- Выберите канал для алертов.
- Copy Webhook URL → вставьте в OpsPulse.
16 Bitrix24 #
- В левом меню — Приложения → Разработчикам.
- Вкладка Другое → Входящий вебхук.
- В правах доступа выберите Чат и уведомления (im).
- Сохраните и скопируйте URL из поля Вебхук для вызова REST API.
- Вставьте URL в настройки OpsPulse — формат Bitrix определится автоматически.
На тарифе START работают Telegram и Email.
17 Частые проблемы #
| Симптом | Вероятная причина |
|---|---|
| Алерты приходят, хотя задача работает | Grace-период меньше реальной длительности задачи. Или в crontab урезанный PATH, и curl не находится — укажите /usr/bin/curl. |
| Пинг уходит, даже когда скрипт упал | Нет set -e, либо использован ; вместо &&. |
| Cron присылает письма с мусором | Забыты флаги -sS у curl. |
| Ничего не работает после переноса задачи в контейнер | В образе нет curl. Поставьте пакет или используйте wget -q -O- URL. |
| Проверка «мигает» up/down | Период короче фактического интервала запуска либо задача запускается не по расписанию. |
Проверить связь вручную можно так — в ответ должен прийти код 200:
curl -sS -o /dev/null -w "%{http_code}\n" \ https://opspulse.ru/ping/UUID
Первая проверка — 10 секунд
Бесплатный тариф не требует карты. 5 проверок, Telegram и Email.
Создать аккаунт