Инженерная задача
Обернуть тяжёлый браузерный рендерер в небольшой сервис с предсказуемым использованием ресурсов и безопасными настройками по умолчанию.
Обернуть тяжёлый браузерный рендерер в небольшой сервис с предсказуемым использованием ресурсов и безопасными настройками по умолчанию.
Backend / Go Engineer. Я спроектировал HTTP-контракт, модель параллелизма, жизненный цикл Chrome, политику ресурсов, наблюдаемость, тесты и контейнерное развёртывание.
HTTP → строгий разбор и валидация → ограниченная очередь → отдельная вкладка Chrome → CDP PrintToPDF → PDF с проверкой размера
Контейнерный сервис с OpenAPI, проверками жизнеспособности и готовности, метриками Prometheus, структурированными логами, корректным завершением работы и автотестами для API, конкурентного доступа и границ безопасности.
Go PDF Renderer — небольшой HTTP-сервис, который управляет намеренно ограниченным экземпляром headless Chrome. Главная задача была не в самом создании PDF — Chrome это уже умеет, — а в том, чтобы сделать HTML-рендеринг предсказуемым сервисом: ограничить тяжёлую браузерную нагрузку, корректно прокидывать таймауты и отмены, строго валидировать входные данные, не позволять присланному HTML превращаться в произвольный сетевой клиент и дать достаточно операционных сигналов для нормального развёртывания.

Chrome запускается один раз и переиспользуется, поэтому сервис не несёт накладные расходы запуска браузера на каждый запрос. Каждый рендеринг получает отдельную вкладку, а HTTP-слой через семафор ограничивает число активных задач. Отдельный таймаут ожидания в очереди отклоняет новые запросы при насыщении сервиса и не позволяет очереди расти бесконечно.
Отмена запроса и дедлайн рендеринга передаются в контекст вкладки, поэтому отменённая или зависшая работа действительно прекращается в браузере. Дополнительно ограничены размеры тела запроса и итогового PDF; параметры рендеринга нормализуются до запуска, а результат проверяется перед отправкой клиенту.

Удалённый сетевой доступ запрещён по умолчанию. Если нужны внешние ресурсы, перехват запросов Chrome Fetch разрешает только явно указанные хосты; адреса частных сетей, loopback, link-local и другие непубличные IP остаются заблокированными. JavaScript также выключен, пока его явно не разрешат в конфигурации.
HTTP-слой следует той же модели: строгий JSON-декодер отклоняет неизвестные поля, имя файла очищается от опасных путей и управляющих символов, ключи API сравниваются за постоянное время, а разрешённые источники CORS задаются явно. Более свободное поведение везде включается только явно, а не используется по умолчанию.

Сервис публикует проверки жизнеспособности и готовности Chrome, информацию о версии и сборке, метрики Prometheus, контракт OpenAPI и встроенный Swagger UI. Структурированные JSON-логи и идентификаторы запросов позволяют разбирать ошибки без тяжёлого фреймворка вокруг рендерера.
Для развёртывания используется многоэтапный Docker-образ со статическим бинарным файлом Go, Chromium Headless Shell, отдельным непривилегированным пользователем и проверкой состояния контейнера. SIGINT/SIGTERM запускают ограниченное по времени корректное завершение HTTP-сервера, после чего закрывается долгоживущий процесс браузера.
В репозитории есть модульные тесты API и проверки параметров, проверки гонок, отдельные тесты политики безопасности и опциональный набор интеграционных тестов с браузером. CI, Docker/Compose, контракт OpenAPI 3.1 и документированная модель угроз делают проект законченным сервисом, а не просто примером кода.