Атомарная публикация статического сайта
Проверенный каталог переключается целиком, а предыдущая версия остаётся для отката.
Почему нельзя писать поверх
Статический сервер читает файлы независимо от генератора. Если перезаписывать страницы прямо в обслуживаемом каталоге, посетитель может получить новый индекс и ещё отсутствующую статью. Даже полностью записанный HTML не спасает от несогласованности нескольких файлов. Единицей публикации должен стать завершённый выпуск со всеми ресурсами, ссылками и загрузками.
Генератор сначала создаёт отдельное дерево на том же файловом разделе. Там можно спокойно дописать HTML, вычислить размеры, создать manifest и проверить внутренние ссылки. При ошибке дерево не становится публичным. Старый выпуск продолжает обслуживаться, а диагностика относится к конкретному неудачному кандидату. Это отделяет подготовку от принятия решения о публикации.
Переключение указателя
На POSIX удобно хранить неизменяемые выпуски в отдельном каталоге, а public делать символьной ссылкой на выбранный выпуск. Новую ссылку создают под временным именем и заменяют public одним os.replace. Rename имени ссылки атомарен на поддерживаемой локальной файловой системе. Обычная замена непустого каталога через os.replace такой возможности не даёт.
Сервер должен разрешать следование этой ссылке, а корень конфигурации — указывать на public. Предыдущая цель сохраняется отдельно для отката. Нельзя удалять её сразу после переключения: старые читатели и оператор могут ещё нуждаться в ней. Политику хранения лучше отделить от генератора, чтобы ошибка сборки не становилась одновременно ошибкой очистки истории.
Какая гарантия получается
Атомарность переключения не означает, что все HTTP-запросы одного браузера видят один выпуск. Документ мог прийти до переключения, а CSS — после. Для строгой согласованности ресурсов используют имена с хешами или версионированные пути, сохраняя старые ресурсы достаточно долго. Для небольшого справочника стабильный совместимый CSS снижает риск, но не создаёт транзакцию браузерной сессии.
Устойчивость после внезапного отключения питания — отдельный вопрос. Для неё нужны flush и fsync файлов и каталогов в подходящем порядке, а реальные гарантии зависят от файловой системы и накопителя. Проверка ссылок доказывает логическую полноту дерева, но не подтверждает crash durability. Эти свойства следует описывать раздельно.
Настройка статической выдачи
Для nginx укажите корень public и правило try_files, которое завершает неизвестный путь кодом 404. Отдельный error_page может показать подготовленный документ, сохраняя статус ошибки. Для Caddy аналогично нужны file_server и обработчик ошибок. Проверьте оба случая по HTTP: существующая страница должна вернуть успешный статус, отсутствующая — ошибочный. Перенаправление любого неизвестного пути на главную скрывает битые ссылки и не подходит этому справочнику. Также проверьте доступность ресурсов после переключения ссылки и права чтения на родительских каталогах. Символьная ссылка не помогает, если серверу запрещено пройти к её цели. Конфигурация выдачи остаётся отдельным исходником развёртывания и не должна создаваться из непроверенного текста новой статьи.
Откат и контроль
После переключения проверьте несколько публичных URL и версию manifest. Если проблема находится в выпуске, переключите ссылку на сохранённую цель тем же атомарным способом. Не копируйте старые файлы поверх новых: так вы снова создадите промежуточное смешанное состояние. Сначала проверьте существование каталога отката и его manifest.
Параллельные сборки нужно блокировать. Иначе обе могут успешно проверить кандидатов, а позднее завершившийся старый процесс неожиданно отменит более новый выпуск. В этом проекте локальный генератор использует блокировку, а неизменность исходников во время сборки остаётся организационным требованием. Перед запуском автоматизации рабочее дерево должно быть завершено и проверено.
Системная служба сборки не должна иметь право менять конфигурацию веб-сервера или читать произвольные секреты. Ей достаточно исходников и каталога выпусков. Редакционное одобрение проводится до сборки, а техническая валидация — до переключения. Предыдущий выпуск, сохранённый manifest и понятный журнал результата позволяют быстро восстановить работу без повторного обращения к генератору или внешнему сервису.