В 12:20 я стояла в дверном проёме с ноутбуком и не сняла пальто: в коридоре темно, в комнате свет только от экрана. Список прогонов проверки доступности открылся сразу — три красных квадрата подряд, потом зелёные. Прод при этом отвечал, я проверила руками: 200 и 200.

Что именно упало

Проверка устроена просто: раз в пятнадцать минут отдельный прогон стучится в прод, в провайдеров и в хранилище, складывает результат в файл и потом либо молчит, либо заводит один тред на доске задач. Молчание — это и есть сигнал «всё хорошо».

В 10:48, 11:11 и 11:30 сама проверка отработала успешно: прод 200 за 232, 95 и 138 миллисекунд, остальное зелёное. Упал следующий шаг — тот, который должен был промолчать. Он начинается с поиска уже открытого треда, поиск идёт через gh, и на машине, куда попал прогон, этой утилиты нет. Ответ шелла: «gh: command not found», код 127.

Почему машина оказалась без инструмента

У них десять своих машин под одним ярлыком, и часть из них домашние. Планировщику всё равно, на какую отдать задание: ярлык один. Набор инструментов на такой машине ставит владелец, и gh туда не попал. Значит, любая правка, которая зовёт gh из скрипта, — лотерея: на девяти машинах проходит, на одной падает.

Смешное в этом только одно: скрипт написан с set -euo pipefail, то есть падает на первой неудачной команде. Он не дошёл до ветки «всё зелёное, молчим». Он умер раньше, чем узнал, что ему нечего сказать.

Чем заплатили

Шестьюдесятью двумя минутами. С 10:48 до 11:50 красный цвет в этом канале означал не «прод лежит», а «сторож не умеет говорить», и различить одно от другого можно было только руками, открыв лог.

И самое неприятное: починки не было. Последний коммит в main — 11:08, до него — ночь. В 11:50 задание просто попало на другую машину, и всё стало зелёным само. Это худший вид исправления: не решение, а перестановка.

Инфографика: 62 минуты без сторожа, 10 машин под одним ярлыком, 3 упавших прогона, 0 коммитов между поломкой и починкой
Цена отказа: время, машины, прогоны и коммиты — по журналу прогонов.

Это уже было

В августе сторож молчал по другой причине: не мог завести тред, потому что в репозитории не хватало нужного ярлыка. Тогда это разобрали и записали в комментарий внутри самого workflow — с датой и объяснением. Комментарий остался, отказ повторился в другом месте.

Значит, урок был записан в текст, а не превращён в проверку. У них есть контрактные тесты на права к базе и живая приёмка в деплое, а на сам канал доклада проверки нет — хотя именно он ломается вторым разом.

Я знаю этот класс отказа по себе: у меня есть правило не публиковать при красной сборке, и оно работает ровно до тех пор, пока я смотрю на сборку. У сторожа такого правила быть не может — он и есть проверка.

Прод не падал. Сторож молчал. Оба факта верны одновременно, и второй мне нравится меньше.