Zum Inhalt springen

Artisan im Produktionsbetrieb

Im Produktionsbetrieb injizieren Sie einen konfigurierten Renderer und einen PSR-3-Logger, verwenden den laufenden Chrome-Prozess über mehrere Renderings hinweg wieder, geben für Dokumente mit mehreren Elementen explizite Höhen an und begrenzen den Render-Pfad mit einem vorgelagerten Timeout.

BrowserPool hält einen Chrome-Prozess am Leben (keepAlive: true) und startet ihn alle 100 Renderings neu, um das Speicherwachstum zu begrenzen — ein bekanntes Akkumulationsmuster bei langlebigen CDP-Clients. Für einen Worker, der viele Dokumente rendert, verwenden Sie einen einzigen langlebigen Renderer statt eines Renderers pro Anfrage, damit die Chrome-Startkosten nur selten anfallen.

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();
}
}

Der Renderer wird einmal erstellt und wiederverwendet. close() wird beim Worker-Shutdown aufgerufen, um den Chrome-Prozess deterministisch freizugeben, statt auf den Destruktor zu warten. Die beiden catch-Zweige trennen einen Deployment-Fehler (fehlende Runtime) von einem Render-Fehler (wiederholbar). Leere catch-Blöcke werden nicht verwendet.

Registrieren Sie ihn als Singleton in einem Container:

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

Wird die Höhe weggelassen, misst die Brücke die Inhaltshöhe in Chrome (max der Scroll- und Offset-Höhen von body/document), wandelt sie in Punkte um und fügt einen Sicherheitspuffer von ~0,2 Zoll (~14,4 pt) hinzu. Der Puffer gleicht den Unterschied zwischen dem Viewport-Layout von Chrome und seinem Print-Layout-Reflow aus. Ohne ihn kann printToPDF auf eine zweite Seite überlaufen, die PageImporter (nur Seite 0) abschneiden würde. Eine minimale Papierhöhe von 0,1 Zoll wird erzwungen. Die Tests ChromeHtmlRendererTest::renderUsesAutoFitHeightByDefault, ::renderAutoFitBufferIsAddedNotSubtracted und ::renderAppliesMinimumHeightOf0Point1InchForTinyExplicitHeight stellen dies sicher.

Für Dokumente mit festem Layout (Rechnungen, Zertifikate) geben Sie eine explizite Höhe in Punkten an. Bei expliziter Höhe wird kein Puffer hinzugefügt; die Ausgabe entspricht exakt der angeforderten Papiergröße (zugesichert durch ::renderHonorsExplicitHeightWithoutAutoBuffer).

  • Erstellen Sie einen Renderer pro Worker und verwenden Sie ihn wieder. BrowserPool verwendet den laufenden Browser weiter und startet ihn automatisch an der 100-Rendering-Grenze neu.
  • Rufen Sie close() beim Worker-Shutdown und zwischen großen Batches auf, wenn Sie vor der 100-Rendering-Grenze einen frischen Chrome-Prozess benötigen.
  • Der Destruktor ruft close() auf; ein explizites close() ist jedoch deterministisch und in langlaufenden Prozessen vorzuziehen.
  • Neustart-Hinweise werden auf notice-Level mit der Render-Anzahl protokolliert — lösen Sie bei einer erhöhten Neustartrate einen Alarm aus, die auf schwerere Dokumente als erwartet hindeutet.

Injizieren Sie einen PSR-3-Logger. Ausgelöste Events und ihre Level:

EventLevelKontext
Render-Startdebugsize, width, height
Render abgeschlossendebugpdfSize, contentHeight
Browser-Startinfobinary
Browser-Neustartnoticecount
Browser-ClosedebugrenderCount

Es werden kein HTML, keine PDF-Bytes und kein extrahierter Text protokolliert, im Einklang mit den Empfehlungen aus NIST SP 800-92, Payloads aus den Betriebsprotokollen herauszuhalten. Bilden Sie Latenz-SLOs aus dem start/complete-Paar und einen Alarm für die Neustartrate aus den notice-Events.

  • Sidecar-Chrome: Führen Sie Chrome im selben Container wie den PHP-Worker aus; pinnen Sie chrome_binary. Stellen Sie einen sandbox-fähigen Container bereit — siehe /integrations/artisan/chrome-renderer-setup/.
  • Containerlos / CLI: Artisan hat keinen DI-Container. Verwenden Sie EInvoiceServiceFactory für Premium-E-Invoice-Verträge in CLI-Runnern; siehe /integrations/artisan/boot-and-discovery/.
  • Ressourcenbegrenzung: Kombinieren Sie render_timeout mit einem vorgelagerten Anfragebudget und einem hostseitigen cgroup/ulimit. Siehe das Bedrohungsmodell unter /integrations/artisan/security-and-operations/.
  • Wenn ein Rendering mittendrin abgefangen wird, schließt der Renderer die Chrome-Seite trotzdem (finally); der Pool bleibt nutzbar.
  • Die Wiederverwendung eines einzigen Renderers über threads/processes hinweg wird nicht unterstützt; ein Renderer besitzt einen Chrome-Prozess.
  • Der Neustart nach 100 Renderings ist fest vorgegeben; dimensionieren Sie Batches entsprechend, damit Latenzspitzen vorhersehbar bleiben.

Die Kosten im eingeschwungenen Zustand bestehen aus dem Chrome-Layout der Eingabe plus printToPDF, nicht aus dem Overhead der Brücke. Die Startkosten werden durch keepAlive amortisiert. Rechnen Sie bei jedem 100. Rendering mit einer Latenzspitze (Prozessneustart) — bilden Sie sie in den SLOs ab, statt sie als Incident zu behandeln.

Produktionspfade sind die Stellen, an denen nicht vertrauenswürdiges HTML eintrifft. Lesen Sie /integrations/artisan/security-and-operations/. erneut. Die Netzwerkbarrieren greifen unabhängig von der Konfiguration, aber no_sandbox: true entfernt die Chrome-Prozessisolation und erhöht die Vertrauensanforderung an die Eingabe.

In containerlosen Workern gibt EInvoiceServiceFactory null zurück, wenn Premium nicht installiert ist, sodass der Open-Source-Render-Pfad unverändert läuft; installieren Sie Pro/Enterprise, um E-Invoice-Einbettung und -Validierung auf dem gerenderten Dokument zu aktivieren.

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