Watchdog: контроль зависания сценариев и устройств
Концепция Watchdog Timer (WDT) и её роль в автоматизации
> ℹ️ Информация: Термин 'Watchdog' (сторожевой пёс) пришел из схемотехники, где специальные микросхемы следили за 'пульсом' процессора и перезапускали его в случае зависания. В современных системах автоматизации этот принцип успешно применяется на программном уровне.
Watchdog Timer (WDT) — это механизм контроля, предназначенный для автоматического обнаружения и реагирования на зависания программ или отказ оборудования. Его работа основана на простой, но чрезвычайно надежной аналогии со сторожевым псом: система или её компонент, за которым ведется наблюдение, должен регулярно посылать сигнал "я в порядке". Этот сигнал принято называть сигналом "пульса" или heartbeat."Сторожевой пёс" представляет собой таймер, который непрерывно отсчитывает время в обратном порядке. Каждый приходящий heartbeat-сигнал сбрасывает этот таймер на его первоначальное значение. Если по какой-либо причине сигнал не приходит в течение установленного времени (таймаута), таймер достигает нуля. Это событие называется "укусом сторожевого пса" (watchdog bite) и инициирует заранее определённую процедуру восстановления.
В контексте платформы автоматизации HI, основанной на контроллерах с Linux и Node-RED, WDT помогает обнаруживать и обрабатывать несколько типов сбоев:
Важность применения WDT напрямую зависит от критичности контролируемой системы. Для второстепенных задач, таких как сбор статистики по влажности в кладовой, его отсутствие не приведет к катастрофе. Однако для ключевых подсистем умного дома или промышленного объекта использование Watchdog является обязательным элементом обеспечения отказоустойчивости:
- Управление климатом: Если сценарий управления котлом или чиллером зависнет, WDT может перевести систему в безопасный режим или перезапустить сценарий, предотвращая перегрев, замерзание или перерасход энергии.
- Системы безопасности: Контроль доступности датчиков движения, открытия дверей или IP-камер. В случае отказа датчика система должна немедленно уведомить владельца и, возможно, активировать резервные контуры.
- Управление питанием: Мониторинг "умных" розеток или модулей реле. Если устройство, подключенное к розетке (например, сетевой шлюз), перестает отвечать, WDT может инициировать его перезагрузку по питанию.
Таким образом, Watchdog Timer является не просто инструментом, а фундаментальной концепцией построения надежных систем, позволяющей перейти от пассивного ожидания сбоя к его проактивному обнаружению и автоматической нейтрализации.
---
Подготовка к работе
> ℹ️ Необходимые компоненты: Для выполнения практической части этого урока убедитесь, что у вас установлен узел `node-red-contrib-watchdog` через `Меню -> Manage Palette -> Install`.
---
Программная реализация: Узел `node-red-contrib-watchdog`
Для реализации программного WDT в среде Node-RED используется специализированный узел из палитры `node-red-contrib-watchdog`. Он полностью инкапсулирует логику таймера, сброса и "укуса", позволяя инженерам сосредоточиться на логике восстановления.
> 💡 Подсказка: Выбирайте таймаут WDT с запасом. Он должен быть как минимум в 2-3 раза больше максимального ожидаемого интервала между heartbeat-сообщениями, чтобы избежать ложных срабатываний из-за кратковременных сетевых задержек. Например, если устройство шлет данные каждые 30 секунд, установите таймаут на 90-120 секунд.
Установка и базовые настройки
Установка узла стандартна и производится через редактор Node-RED: `Меню -> Manage Palette -> Install` и введите в поиске `node-red-contrib-watchdog`.
После установки узел `watchdog` появляется в палитре. Рассмотрим его ключевые настройки:
- Timeout: Основной параметр. Задает время в выбранных единицах, по истечении которого произойдет "укус".
- Units: Единицы измерения таймаута (миллисекунды, секунды, минуты, часы). Для большинства задач автоматизации оптимальны секунды или минуты.
- Handle first message on...: Определяет, как узел отреагирует на первое пришедшее сообщение. Рекомендуемое значение — `start of timeout period`. Это означает, что таймер запустится сразу же, как только придет первый heartbeat.
- Name: Осмысленное имя, отражающее, что именно контролирует данный узел. Например, "WDT: Датчик CO2 в спальне" или "WDT: Сценарий полива".
Формирование 'heartbeat' сообщений
Узел `watchdog` устроен максимально просто: любое сообщение, пришедшее на его вход, считается heartbeat-сигналом и сбрасывает таймер. Содержимое `msg.payload` при этом игнорируется, но само сообщение `msg` проходит без изменений на первый выход узла. Это позволяет встраивать `watchdog` в существующие потоки, не нарушая их логику.
[Источник данных] --(heartbeat)--> [watchdog] --(данные без изменений)--> [Дальнейшая обработка]
|
+---("укус" при сбое)--> [Логика восстановления]
Обработка 'укуса' (watchdog bite)
Самая важная часть — это то, что происходит, когда таймер не был сброшен вовремя. В этом случае `watchdog` генерирует новое сообщение на своем втором выходе. Это и есть "укус".
Сообщение, генерируемое при "укусе", имеет следующую структуру:
{
"payload": "Watchdog timeout! Name: 'WDT: Датчик CO2'",
"topic": "",
"_msgid": "..."
}
- `msg.payload` содержит текстовое сообщение о сработавшем таймере, включая имя, которое вы задали узлу.
- `msg.topic` по умолчанию пуст, но его можно настроить для удобства маршрутизации.
Именно это сообщение и становится триггером для запуска сценариев восстановления: отправки уведомлений, перезагрузки оборудования, перевода системы в безопасное состояние и журналирования инцидента.
---
Пример 1: Контроль доступности MQTT-устройства
Рассмотрим самый распространенный сценарий: мониторинг доступности беспроводного датчика, который регулярно (например, раз в 60 секунд) отправляет свои показания по протоколу MQTT.
Задача: Контролировать доступность датчика температуры и влажности в гостиной. Если данные от него не поступают в течение 3 минут, отправить тревожное уведомление в Telegram и записать инцидент в базу данных MySQL на контроллере. В качестве дополнительной меры, попытаться перезагрузить датчик, если он запитан от управляемой розетки. Flow Diagram:// Поток мониторинга
[mqtt in]------------------>[watchdog]----->[debug: Heartbeat OK]
(telemetry/livingroom/th) |
+---(timeout)-->[change: Format Alert]--+-->[telegram sender]
|
+-->[function: SQL Log]--->[mysql]
|
+-->[change: Reboot Cmd]-->[mqtt out]
(commands/plugs/plug-05/set)
Реализация потока
* Server: Выбираем MQTT-брокер контроллера HI.
* Topic: `telemetry/livingroom/th` (или топик вашего датчика).
* QoS: `0` или `1`.
* Timeout: `3`
* Units: `Minutes`
* Name: `WDT: Датчик Т/H в гостиной`
* Соединяем `mqtt in` с входом `watchdog`. Первый выход `watchdog` можно подключить к узлу `debug` для визуального контроля проходящих heartbeat'ов.
* Этот узел подключается ко второму выходу `watchdog`.
* Name: `Format Alert Msg`
* Правило: `Set` `msg.payload` `to` `⚠️ Тревога! Датчик температуры/влажности в гостиной не отвечает более 3 минут. Возможен сбой или разряд батареи.`
* Настраиваем узел для отправки `msg.payload` в нужный чат.
* Name: `SQL Log Event`
* Код для формирования SQL-запроса для записи в таблицу `audit_log`:
const device_id = "th-sensor-livingroom";
const event_type = "device_offline";
const description = msg.payload; // Берем текст из предыдущего узла
msg.topic = `INSERT INTO audit_log (timestamp, device_id, event_type, description) VALUES (NOW(), ?, ?, ?)`;
msg.payload = [device_id, event_type, description];
return msg;
* Этот узел подключается к узлу `mysql` для выполнения запроса.
* Name: `Prepare Reboot Cmd`
* Правило: `Set` `msg.payload` `to` JSON:
{
"value": "REBOOT",
"source": "watchdog-th-livingroom",
"ts": 1678886400000
}
> ℹ️ Информация: Контракт сообщения для перезагрузки может отличаться. Некоторые розетки ожидают `{"state":"OFF"}` затем `{"state":"ON"}`. Здесь мы используем гипотетический контракт с командой `REBOOT`.
* `mqtt out`:
* Topic: `commands/plugs/plug-05/set` (топик управления розеткой, питающей датчик).
* Соединяем выход узла `change` с этим узлом.
Теперь система не только обнаружит сбой, но и уведомит администратора, задокументирует его и попытается автоматически устранить.
---
Пример 2: Контроль зависания сложного сценария в Function-узле
Программные WDT полезны не только для контроля внешних устройств, но и для самодиагностики сложных сценариев внутри Node-RED. Узел `Function` — мощный инструмент, но в нем легко допустить ошибку, которая приведет к зависанию: бесконечный цикл, неразрешенный Promise, блокирующая синхронная операция.
> ⚠️ Внимание: Неправильное размещение heartbeat-сигналов внутри кода может маскировать проблему. Размещайте их после потенциально долгих или рискованных операций (например, внешние API-вызовы), а не в начале функции.
Задача: У нас есть сложный узел `Function`, который раз в 5 минут выполняет серию HTTP-запросов к разным внешним API (например, погода, курсы валют, дорожная обстановка), агрегирует данные и формирует отчет. Этот процесс может занять до 30 секунд. Если узел не завершит работу за 60 секунд, нужно считать его "зависшим", отправить уведомление и установить для всех связанных с ним устройств безопасное состояние.Реализация потока
* Сделаем у узла `Function` два выхода. Первый выход (индекс 0) — для результата работы. Второй (индекс 1) — для отправки heartbeat-сигналов.
// Поток контроля сценария
[inject: раз в 5 мин] ---> [Function: Сбор данных с API] --+-- (результат) --> [Обработка отчета]
| |
'--(heartbeat)----------------+--> [watchdog]
|
+-- (timeout) --> [Сценарий восстановления]
* Name: `Сбор данных с API`
* Outputs: `2`
* Код (псевдокод для наглядности):
// Отправляем первый heartbeat в самом начале, чтобы показать, что мы стартовали
node.send([null, { payload: "heartbeat_start" }]);
try {
// Имитация долгого API-запроса №1
const weather_data = await some_async_http_request("api.weather.com");
// Отправляем heartbeat после первого успешного шага
node.send([null, { payload: "heartbeat_step1" }]);
// Имитация долгого API-запроса №2
const traffic_data = await some_async_http_request("api.traffic.com");
// Отправляем heartbeat после второго успешного шага
node.send([null, { payload: "heartbeat_step2" }]);
// Формируем финальный отчет
const report = { weather: weather_data, traffic: traffic_data };
// Отправляем результат на первый выход
node.send([{ payload: report }, null]);
} catch (error) {
node.error("Ошибка при сборе данных с API: " + error.message, msg);
// В случае ошибки не отправляем результат, поток прервется
// Watchdog сработает, если ошибка вызовет "зависание"
}
// `return;` используется, т.к. мы отправляем сообщения через node.send()
return;
* Timeout: `60`
* Units: `Seconds`
* Name: `WDT: Сценарий API`
* Подключаем второй выход `Function` ко входу `watchdog`.
* Ко второму выходу `watchdog` подключаем цепочку, аналогичную первому примеру:
* Отправка критического уведомления: `⚠️ Тревога! Сценарий сбора данных с API завис и не отвечает более 60 секунд.`.
* Журналирование инцидента.
* Перевод в безопасное состояние: Отправка команд на исполнительные устройства для установки безопасных значений. Например, если этот API-сценарий управляет уличным освещением, при его сбое можно принудительно включить свет, отправив `ON` в соответствующий MQTT-топик.
Этот подход позволяет контролировать "здоровье" не только внешних устройств, но и внутренней логики самой системы автоматизации.
---
Системный Watchdog в контроллерах HI на базе Linux
До сих пор мы рассматривали программные WDT на уровне Node-RED. Но что, если "зависнет" не отдельный сценарий, а весь процесс Node-RED целиком? Или сам контроллер войдет в неработоспособное состояние? Для этого существует следующий, более глубокий уровень защиты — системный Watchdog.
> 🔗 Связанный материал: Подробная работа с сервисами systemd для обеспечения стабильности разбирается в курсе по администрированию контроллеров HI: `COURSE-12-M01-L04`.
Следует четко различать уровни:
- Программный WDT (в Node-RED): Контролирует конкретное устройство или сценарий. Реализуется узлом `node-red-contrib-watchdog`.
- Системный/Аппаратный WDT (на уровне ОС): Контролирует жизнеспособность критически важных процессов (например, самого Node-RED) или всей операционной системы.
На контроллерах HI под управлением Debian Linux роль системного "сторожевого пса" для процессов выполняет сервисный менеджер `systemd`. Он является процессом с PID 1 и отвечает за запуск, остановку и мониторинг всех системных служб.
`systemd` может автоматически перезапускать сервисы, которые завершили свою работу с ошибкой. Это стандартная практика для обеспечения стабильности работы Node-RED на производственных объектах.
Конфигурация сервиса Node-RED обычно находится в файле `/lib/systemd/system/nodered.service`. Для обеспечения автоматического перезапуска достаточно убедиться, что в секции `[Service]` присутствуют следующие директивы:
[Unit]
Description=Node-RED
After=syslog.target network.target
[Service]
ExecStart=/usr/bin/node-red-start
# Пользователь, от имени которого запускается Node-RED
User=nodered
Group=nodered
Restart=on-failure # <-- Ключевая директива
RestartSec=20s # Пауза перед перезапуском
[Install]
WantedBy=multi-user.target
Директива `Restart=on-failure` указывает `systemd`: "Если процесс Node-RED завершится с кодом ошибки (т.е. упадет), подожди 20 секунд (`RestartSec=20s`) и запусти его снова".
Это обеспечивает базовый уровень отказоустойчивости всей платформы автоматизации. Если некая критическая ошибка в одном из узлов приведет к падению всего процесса Node-RED, `systemd` вернет его в строй в течение нескольких секунд, минимизируя время простоя системы.
---
Резюме и лучшие практики
В этом уроке мы рассмотрели концепцию Watchdog Timer — мощного инструмента для повышения стабильности и отказоустойчивости систем автоматизации.
📋 Ключевые понятия:
- Watchdog Timer (WDT): Механизм, перезапускающий систему или инициирующий процедуру восстановления, если он не получает регулярный сигнал "пульса" (heartbeat).
- Heartbeat: Регулярный сигнал, подтверждающий работоспособность контролируемого компонента.
- "Укус" Watchdog: Событие, происходящее при истечении таймаута, которое запускает сценарий восстановления.
- Эшелонированная надежность: Применение WDT на разных уровнях для создания многоуровневой защиты от сбоев.
Лучшие практики:
* Уровень 1 (Устройство/Сценарий): Программный WDT в Node-RED (`node-red-contrib-watchdog`) для контроля каждого критичного датчика, исполнительного механизма или сложного сценария.
* Уровень 2 (Процесс): Системный WDT на уровне `systemd` для автоматического перезапуска всего сервиса Node-RED в случае его падения.
* Уровень 3 (Система): Аппаратный WDT самого контроллера (если он есть), который перезагрузит всю систему в случае зависания операционной системы.
Что дальше
Мы изучили теоретические основы и практические примеры использования Watchdog. Теперь необходимо закрепить эти знания. В следующих практических частях этого модуля вас ждут лабораторные работы, где вы самостоятельно настроите WDT для контроля Modbus-устройства и создадите отказоустойчивый сценарий с самодиагностикой.