Pular para o conteúdo

Artisan em produção

Em produção, injete um renderizador configurado e um logger PHP Standards Recommendation 3 (PSR-3), reutilize o processo ativo do Chrome entre renderizações, defina alturas explícitas para documentos com múltiplos elementos e limite o caminho de renderização com um timeout upstream.

BrowserPool mantém ativo um processo do Chrome (keepAlive: true) e o reinicia a cada 100 renderizações para limitar o crescimento de memória, um padrão de acúmulo conhecido em clientes Chrome DevTools Protocol (CDP) de longa duração. Para um worker que renderiza muitos documentos, use um único renderizador de longa duração em vez de um renderizador por requisição, para que você pague o custo de inicialização do Chrome apenas raramente.

render-service.php
<?php
declare(strict_types=1);
use NextPDF\Artisan\ChromeHtmlRenderer;
use NextPDF\Artisan\ChromeRendererConfig;
use NextPDF\Artisan\Exception\ChromeNotAvailableException;
use NextPDF\Artisan\Exception\ChromeRenderException;
use Psr\Log\LoggerInterface;
final class ReportRenderer
{
private ChromeHtmlRenderer $renderer;
public function __construct(LoggerInterface $logger)
{
$config = ChromeRendererConfig::fromArray([
'chrome_binary' => getenv('CHROME_BINARY') ?: null,
'render_timeout' => 45,
'max_html_size' => 2_000_000,
'no_sandbox' => (bool) getenv('CHROME_NO_SANDBOX'),
]);
$this->renderer = new ChromeHtmlRenderer($config, $logger);
}
public function render(string $html, float $widthPt, float $heightPt = 0.0): string
{
try {
return $this->renderer->render($html, $widthPt, $heightPt)->getPdfData();
} catch (ChromeNotAvailableException $e) {
// Deployment fault: Chrome runtime missing. Page the on-call owner.
throw $e;
} catch (ChromeRenderException $e) {
// Render-time fault: timeout, crash, empty output. Retryable once.
throw $e;
}
}
public function shutdown(): void
{
$this->renderer->close();
}
}

Crie o renderizador uma vez e depois o reutilize. Chame close() quando o worker for encerrado para liberar o processo do Chrome de forma determinística, em vez de esperar pelo destrutor. Os dois ramos de catch separam uma falha de implantação (runtime ausente) de uma falha em tempo de renderização (passível de nova tentativa). Não use blocos catch vazios.

Conecte-o a um container como um singleton:

$container->singleton(ReportRenderer::class, fn ($c) =>
new ReportRenderer($c->get(Psr\Log\LoggerInterface::class)));

Quando você omite a altura, a ponte mede a altura do conteúdo no Chrome (max das alturas de scroll e offset de body/document), converte o valor em pontos e adiciona uma margem de segurança de ~0.2 polegada (~14.4 pt). Essa margem cobre a diferença entre o layout de viewport do Chrome e o reflow do seu layout de impressão. Sem ela, o printToPDF pode fazer o conteúdo transbordar para uma segunda página que o PageImporter (apenas a página 0) recortaria. A ponte impõe uma altura mínima de papel de 0.1 polegada. Os testes ChromeHtmlRendererTest::renderUsesAutoFitHeightByDefault, ::renderAutoFitBufferIsAddedNotSubtracted e ::renderAppliesMinimumHeightOf0Point1InchForTinyExplicitHeight asseguram esse comportamento.

Para documentos de layout fixo (faturas, certificados), passe uma altura explícita em pontos. Quando a altura é explícita, nenhuma margem é adicionada, e a saída corresponde exatamente ao tamanho de papel solicitado (garantido por ::renderHonorsExplicitHeightWithoutAutoBuffer).

  • Crie um renderizador por worker e o reutilize. BrowserPool reutiliza o navegador ativo e reinicia automaticamente no limite de 100 renderizações.
  • Chame close() no encerramento do worker e entre lotes grandes quando quiser um processo do Chrome novo antes do limite de 100 renderizações.
  • O destrutor chama close(), mas um close() explícito é determinístico e preferível em processos de longa duração.
  • Os avisos de reinício são registrados no nível notice com a contagem de renderizações; gere um alerta diante de uma taxa de reinício elevada, pois ela indica documentos mais pesados do que o esperado.

Injete um logger PSR-3. O renderizador emite estes eventos e níveis:

EventoNívelContexto
Início da renderizaçãodebugsize, width, height
Renderização concluídadebugpdfSize, contentHeight
Inicialização do navegadorinfobinary
Reinício do navegadornoticecount
Fechamento do navegadordebugrenderCount

Nenhum HTML, byte de PDF ou texto extraído é registrado em log. Isso mantém os payloads fora dos logs operacionais e está alinhado com a orientação de conteúdo de log da National Institute of Standards and Technology Special Publication (NIST SP) 800-92. Crie objetivos de nível de serviço (SLOs) de latência a partir do par start/complete e um alerta de taxa de reinício a partir dos eventos notice.

  • Chrome sidecar: execute o Chrome no mesmo container que o worker PHP; fixe chrome_binary. Provisione um container com suporte a sandbox; consulte /integrations/artisan/chrome-renderer-setup/.
  • Sem container / CLI: o Artisan não tem container de injeção de dependência. Use EInvoiceServiceFactory para contratos de e-invoice do Premium em runners de command-line interface (CLI); consulte /integrations/artisan/boot-and-discovery/.
  • Limitação de recursos: combine render_timeout com um orçamento de requisição upstream e um cgroup/ulimit de host. Consulte o modelo de ameaças em /integrations/artisan/security-and-operations/.
  • Um renderizador interrompido no meio de uma renderização ainda fecha a página do Chrome (finally), e o pool permanece utilizável.
  • Reutilizar um renderizador entre threads/processes não é suportado; cada renderizador é dono de um processo do Chrome.
  • O reinício a cada 100 renderizações é fixo; dimensione os lotes levando isso em conta para que os picos de latência permaneçam previsíveis.

O custo em regime permanente é o layout do conteúdo de entrada pelo Chrome mais o printToPDF, não a sobrecarga da ponte. O keepAlive distribui o custo de inicialização entre as renderizações. Espere um pico de latência a cada 100ª renderização (reinício do processo); exponha esse pico nos SLOs em vez de tratá-lo como um incidente.

Os caminhos de produção recebem HTML não confiável. Releia /integrations/artisan/security-and-operations/. As barreiras de rede permanecem ativas independentemente da configuração, mas no_sandbox: true remove o isolamento de processo do Chrome e aumenta o nível de confiança exigido para a entrada.

Em workers sem container, EInvoiceServiceFactory retorna null quando o Premium não está instalado, de modo que o caminho de renderização open-source permanece inalterado. Instale o Pro/Enterprise para habilitar a incorporação e a validação de e-invoice no documento renderizado.

  • /integrations/artisan/quickstart/
  • /integrations/artisan/configuration/
  • /integrations/artisan/security-and-operations/
  • /integrations/artisan/chrome-renderer-setup/
  • /integrations/artisan/troubleshooting/