Валидация и откат конфигурации: полная семантика fail-fast
«Отказать в старте» — лишь половина валидации; вторая половина — «после провала не остаётся обломков». Глава собирает валидацию, откат сборки и отклонения reload в единую карту обороны.
Обзор
13.1 Введение
У ошибок конфигурации три плохих финала: работа «с дефектом» (опаснейший), полузапущенное состояние (трудно отлаживать) и молчаливая правка в неверное поведение (самый коварный). Дизайн XServer перекрывает все три: ошибки старта всегда завершают процесс с именем поля; сборка — транзакция (частичный успех откатывается); изменения в рантайме либо действуют полностью, либо остаются нетронутыми. Эти три фразы и есть данная глава.
13.2 Матрица fail-fast
A-матрица func_test сторожит валидацию старта 21 кейсом — все с утверждением exit=1 и ошибкой, называющей конкретное поле. Покрытие слоится по этапам:
Каждый слой завершается до входа в следующий — ошибка всегда указывает на самый ранний сбой, и вам не приходится гадать, разбирав пять наложенных ошибок.
13.3 Транзакция сборки и откат слушателей
Сборка после валидации (компиляция скриптов → ServiceInit → bind) тоже транзакционна. В func_test есть специальный кейс отката:
конфигурация: plain 8080 + tls 8443, причём 8443 уже занят внешним процессом [xs] server ... http bound on 0.0.0.0:8080 /* сначала успешная привязка */ bind failed (8443) → занятый 8080 полностью откатывается (порт снова можно bind) → процесс завершается, полузапущенных остатков нет
В мультисервисном сценарии так же (глава 11): неудача компиляции скрипта любого server прерывает всю сборку — «трём хорошим дать поработать» не бывает.
13.4 Список отклонений reload
У запросов на изменение в рантайме (reload) свои ворота, явно отклоняющие:
| Изменение | Результат | Причина |
|---|---|---|
изменение значения engine.workers | FAILED | факт уровня процесса нельзя перестроить на ходу |
изменение неизменяемых полей слушателя (например recv_limit) | FAILED (зафиксировано lifecycle-тестами) | изменение параметров слушателя требует пути структурной пересборки |
| структурное изменение (эндпоинты/класс) без handoff | FAILED с подсказкой о рестарте | онлайн-пересборка поддерживает только передачу слота при неизменных эндпоинтах |
| обновление скрипта сервиса класса custom | онлайн-перезагрузка не поддерживается | у «сырых» ресурсов приложения нет терминального lease (том 4) |
| провал компиляции скрипта-кандидата | FAILED, старое поколение продолжает обслуживать | сначала компиляция, потом замена — откат есть семантическая гарантия |
Разрешённые горячие пути: обновление содержимого скриптов, горячая замена сертификатов (глава 12) и обновление конфигурации на тех же эндпоинтах (передача слота слушателя). Принятые намерения сливаются по latest-wins — старые завершаются как SUPERSEDED, просроченные конфигурации не выстраиваются в очередь.
13.5 Контракт
- Старт: пять слоёв валидации по порядку, сообщение о самой ранней ошибке, exit=1, без остатка.
- Сборка: компиляция/Init/bind — транзакция; частичный успех обязательно откатывается.
- Рантайм: пять классов отклонений reload + latest-wins; у успеха ровно одна форма — «действует полностью».
Частые ошибки
- Симптом
- После подачи перезагрузки State=FAILED и срабатывает эксплуатационная тревога.
- Причина
- FAILED — семантика отклонения: старое поколение цело, сервис не прерывался — это значит «изменение не вступило в силу», а не «отказ сервиса». Читайте XS_ReloadResult.Message ради причины.
- Симптом
- Подряд поданы три перезагрузки — в сервисе видна только последняя.
- Причина
- Слияние latest-wins: старые намерения того же server вытесняются (SUPERSEDED), предел pending — 64. Это защита от «просроченных конфигураций из очереди».
Упражнения
По кейсу 13.3 займите TLS-порт и запустите; убедитесь, что занятый порт открытого текста откатился (netstat после выхода подтвердит освобождение).
По очереди подайте перезагрузки с изменением workers и recv_limit; зафиксируйте оба сообщения FAILED.
Циклом подайте 20 перезагрузок «скрипта с ошибкой компиляции» (см. образец reload-бомбы drill), наблюдая выживание старого поколения и опрос результатов.
Итоги
| Тезис | Вывод |
|---|---|
| Пять слоёв | структура→поля→уникальность→ресурсы→семантика, побеждает самая ранняя ошибка |
| Транзакция сборки | частичный успех обязательно откатывается, полузапущенных остатков нет |
| Ворота reload | пять отклонений (workers / неизменяемые слушатели / структура / custom / провал компиляции) |
| Семантика FAILED | отклонено ≠ сломано: старое поколение цело, Message называет причину |
| latest-wins | старые намерения server уходят в SUPERSEDED, очереди нет |
- учебник xrt · HTTP-сервер — дизайн тайм-аутов и защиты от медленных атак на уровне библиотеки