Сине-зелёные выкаты и еженедельные обновления зависимостей остаются «скучными» только если ваш шлюз OpenClaw может исчезнуть, не обрывая наполовину выполненные вызовы инструментов. В 2026 году операторы ждут пути graceful shutdown в духе облачных практик: перевернуть readiness, чтобы балансировщики не слали новый трафик, остановить цикл accept, дренировать текущие HTTP- и стриминг-вызовы в явных временных рамках, затем выйти с нулевым кодом после сброса метрик и логов. Здесь разобраны readiness и liveness, бюджеты дренажа без голодания длинных выгрузок CRM, связь остановки с circuit breaker и очередью недоставленных сообщений (DLQ), роль диагностики таймаутов чтения и зависаний, а также то, как мониторинг здоровья должен показывать состояние draining синтетическим пробам.
Ориентир по цене: отрепетировать хореографию SIGTERM на выделенном Mac mini у MacHTML примерно за 16,9 $ в сутки дешевле, чем деплой, где launchd через ~30 секунд переходит к SIGKILL, пока двенадцать вызовов ещё держат блокировки БД.
Сигналы, launchd ExitTimeout и значения по умолчанию
На macOS launchd посылает SIGTERM при launchctl bootout или когда обновление зависимостей перезапускает задачу. Без увеличенного ExitTimeout следует SIGKILL после платформенной паузы—часто шаблоны упоминают около 30 секунд, но проверяйте launchctl print gui/$UID/ваш.plist. У Linux-контейнеров другие умолчания; смешанные флоты без репетиции гарантируют сюрпризы.
Обработчики сигналов должны атомарно выставить shutting_down, закрыть простаивающие keep-alive и потокобезопасно запустить таймер дренажа. Тяжёлую работу не держите внутри обработчика—отправьте событие в главный цикл, чтобы не ломать TLS.
Зафиксируйте два бюджета: внешний (что верит балансировщик) и внутренний (что нужно пулу). Если внутренний больше—сначала удлините задержку снятия с регистрации или укоротите таймауты инструментов.
Для российских и СНГ-команд с жёсткими окнами обслуживания важно согласовать эти секунды с публичным статусом: «чистый» дренаж, выходящий за объявленное окно, бьёт по доверию так же, как аварийный kill.
Readiness против liveness во время дренажа
Liveness истинна, пока процесс ещё может продвигаться; readiness должна стать ложной, как только вы отказываетесь от новой работы. Путаница ради удобства даёт каскады: фронт продолжает назначать сессии на узел, который уже не должен их принимать.
Дайте /readyz, отвечающий 503 с JSON вроде {"draining":true,"in_flight":14,"deadline_ms":12000}, чтобы синтетика строила кривые. Сочетайте с рекомендациями из мониторинга здоровья шлюза.
Продуктовым командам полезны дашборды, где пики маркетингового трафика накладываются на in_flight—так видно, почему пятничный послеобеденный выкат рискованнее.
Остановка accept без лавины сбросов
Мгновенное закрытие listening-socket может оборвать рукопожатия TLS через RST. Лучше прикладной шлюз с 503 и Retry-After: 5, пока существующие соединения завершают текущий запрос. Для HTTP/2 аккуратно выстроите GOAWAY: объявите нулевой потолок потоков, дождитесь открытых, затем закройте.
Для WebSocket-мостов инструментов отправьте прикладное server_shutdown и подсказку backoff до закрытия сокета, чтобы агенты не ударили стадом по следующему поду.
Проверьте idle-timeout управляемых прокси: если он короче вашего дренажа, «здоровые» keep-alive обрежутся раньше времени и вызовут преждевременные ретраи.
Пулы воркеров, дедлайны и стриминг
Разделите бюджет: например 60 % на обычный REST, 30 % на long-poll/стриминг, 10 % на админ-хуки вроде scrape метрик. Если один арендатор монополизирует воркеры, сохраняйте лимиты параллелизма по арендаторам и во время дренажа.
При активном стриминга модели не принимайте новые ходы, но позвольте текущему SSE-дожиму завершиться по байтам или по под-дедлайну, скажем 20 секунд. Обрывы фиксируйте как SHUTDOWN_TRUNCATED_STREAM.
Интеграции с отечественными CRM и биллингом часто дают длинные хвосты длительности—лейблируйте по имени инструмента, чтобы знать, что укорачивать первым.
Балансировщики и Retry-After
После смены readiness подождите минимум один интервал проб—часто 5 секунд—прежде чем останавливать accept. В мультирегионе учитывайте DNS TTL, указывающий отстающим на старые инстансы. Retry-After держите согласованным со сторией идемпотентности SDK.
При L4 pass-through новые HTTP-запросы могут приезжать по старым keep-alive; ведите счётчик поколения на соединение и отвечайте Connection: close на новые запросы после старта shutdown, завершая активный запрос на том же сокете.
Если облачный провайдер тарифицирует поминутно, заложите стоимость длинного дренажа в runbook.
Метрики, логи и постмортемы
Экспортируйте gauge gateway_in_flight_total, counter gateway_shutdown_events_total{result} с метками clean, deadline_exceeded, forced_kill, гистограмму gateway_shutdown_duration_seconds от flip readiness до выхода процесса—так SLO покажет, жив ли бюджет 45 секунд неделя к неделе.
В структурных логах храните настроенную паузу, пик in_flight и самый медленный инструмент. Кладите рядом с тикетами деплоя.
Тревога, если clean семь дней ниже 99 % при росте частоты выкатов.
Для комплаенса иногда нужно доказать, что не осталось «полузапросов» с ПДн; ваши временные ряды становятся техническим приложением к отчёту.
Веса канареек при rolling-рестартах
Rolling умножает частоту остановок. Ограничьте одновременно дренируемые инстансы 20 % флота без доказательств запаса по синтетике.
Автооткат, если пятиминутный 5xx > 1 %, пока инстанс публикует draining: вернитесь к последней хорошей таблице весов и позовите владельца деплоя.
Канарейки только по HTTP-статусу часто пропускают полуоткрытые вызовы инструментов—добавьте бизнес-KPI.
Согласование с circuit breaker
Во время дренажа нужно меньше проб, а не больше. Настройте circuit breaker: удлините half-open или держите открытым для уже больных зависимостей.
Продюсеры DLQ и идемпотентный enqueue
Если остановка гоняется с обработчиками ошибок, пишущими в DLQ, enqueue должен быть идемпотентен или дедуплицирован. Иначе повтор TCP без идемпотентности дублирует записи. См. дизайн DLQ для полей конверта, переживающих выход процесса.
Матрица: жёсткий SIGKILL и graceful drain
| Сценарий | Жёсткий SIGKILL | Graceful drain |
|---|---|---|
| Транзакция БД | Риск частичного коммита | Ожидание или явный rollback-hook |
| Стриминг токенов модели | Обрыв mid-sentence | Ограниченное ожидание + флаг усечения |
| Латентность деплоя | короче | обычно +5–45 с |
| Доверие операторов | низкое | высокое, если метрики доказывают дренаж |
Чеклист выката
- Дашборд для JSON дренажа на
/readyz. - Согласовать
ExitTimeoutс внутренней математикой + 10 с запаса. - Интеграционный тест
SIGTERMс ≥ 50 синтетическими вызовами. - Порядок GOAWAY HTTP/2 под нагрузкой (
h2load). - Шаблон постмортема с CSV таймлайна дренажа.
Вопросы и ответы
Влияет ли systemd KillMode на OpenClaw?
На смешанных флотах задокументируйте mixed против control-group—меняется, какие дочерние процессы получают сигналы.
Можно ли дренаж сделать бесконечным?
Нет—бесконечный дренаж скрывает зависшие воркеры. Используйте диагностику зависаний.
Важны ли Windows-ноутбуки разработчиков?
Только если вы поставляете Windows-шлюзы; для партнёров на MacBook macOS-репетиция остаётся ценной.
Команды, уже использующие OpenTelemetry, могут добавить атрибут drain.phase к активным трассам в момент flip readiness—тогда в постмортеме сразу видно, какие спаны инструментов обрезало окно ExitTimeout, а не бизнес-ошибка.
Если вы поднимаете несколько шлюзов за обратным прокси на одном облачном Mac mini, синхронизируйте порядок остановки: сначала снимайте с балансировщика самый «шумный» инстанс по метрике in_flight, иначе оставшиеся узлы получат внезапный всплеск ретраев и сами выйдут за бюджет дренажа. Документируйте эту перестановку в runbook рядом с командами launchctl, чтобы дежурный не импровизировал под давлением инцидента.
Для редких интеграций с локальными очередями сообщений на том же хосте проверьте, что брокер получает сигнал о закрытии продюсера до того, как шлюз отдаст последний ответ клиенту: иначе «чистый» HTTP-дренаж маскирует ещё висящие публикации в памяти агента. Этот шаг легко забыть при переходе с Linux-контейнеров на macOS LaunchAgent.
Наконец, фиксируйте в репозитории версию шлюза и версию CLI OpenClaw рядом с таблицей таймаутов дренажа: рассинхрон, который всплывает только при остановке, иначе превратится в долгую охоту за призраками на проде без чёткой корневой причины, понятного виновника релиза и согласованного плана отката.
Graceful shutdown—это место, где культура надёжности встречается с измеримыми секундами. Арендованный у MacHTML Mac mini примерно за 16,9 $/сутки даёт нативную доставку сигналов macOS, запас Apple Silicon для soak и SSH/VNC, чтобы смотреть таймлайны launchd до клиентского трафика.
Репетиция остановки шлюза OpenClaw на облачном Mac mini
ExitTimeout, сценарии сбоев h2load и переключения readiness на реальном сетевом стеке macOS до сине-зелёного переключения.