Artisan en production
En un coup d’œil
Section intitulée « En un coup d’œil »En production, injecte un renderer configuré et un logger PSR-3, réutilise le processus Chrome actif d’un rendu à l’autre, fournis des hauteurs explicites pour les documents à plusieurs éléments et encadre le chemin de rendu avec un timeout en amont.
Aperçu conceptuel
Section intitulée « Aperçu conceptuel »BrowserPool maintient un seul processus Chrome actif (keepAlive: true) et le redémarre tous les 100 rendus pour borner la croissance mémoire — un comportement d’accumulation connu chez les clients CDP à longue durée de vie. Pour un worker qui rend de nombreux documents, tu veux un seul renderer de longue durée, plutôt qu’un par requête, afin de ne payer que rarement le coût de démarrage de Chrome.
Exemple de code — Production
Section intitulée « Exemple de code — Production »<?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(); }}Le renderer est construit une seule fois, puis réutilisé. close() est appelé à l’arrêt du worker pour libérer le processus Chrome de façon déterministe, plutôt que d’attendre le destructeur. Les deux branches catch séparent une faute de déploiement (runtime manquant) d’une faute au moment du rendu (réessayable). Aucun bloc catch vide n’est utilisé.
Câble-le dans un conteneur comme singleton :
$container->singleton(ReportRenderer::class, fn ($c) => new ReportRenderer($c->get(Psr\Log\LoggerInterface::class)));Gestion de la hauteur
Section intitulée « Gestion de la hauteur »Quand la hauteur est omise, le pont mesure dans Chrome la hauteur du contenu (max des hauteurs scroll et offset de body/document), la convertit en points et ajoute une marge de sécurité d’environ 0,2 pouce (~14,4 pt). La marge absorbe la différence entre la mise en page du viewport de Chrome et son reflow en mode impression. Sans elle, printToPDF risque de déborder sur une deuxième page que PageImporter (page 0 uniquement) couperait. Une hauteur de papier minimale de 0,1 pouce est appliquée. Les tests ChromeHtmlRendererTest::renderUsesAutoFitHeightByDefault, ::renderAutoFitBufferIsAddedNotSubtracted et ::renderAppliesMinimumHeightOf0Point1InchForTinyExplicitHeight vérifient cela.
Pour les documents à mise en page fixe (factures, certificats), passe une hauteur explicite en points. Aucune marge n’est ajoutée quand la hauteur est explicite, et la sortie correspond exactement à la taille de papier demandée (vérifié par ::renderHonorsExplicitHeightWithoutAutoBuffer).
Workers par lots
Section intitulée « Workers par lots »- Construis un seul renderer par worker ; réutilise-le.
BrowserPoolréutilise le navigateur actif et redémarre automatiquement à la limite des 100 rendus. - Appelle
close()à l’arrêt du worker et entre deux gros lots si tu veux obtenir un processus Chrome neuf avant la limite des 100 rendus. - Le destructeur appelle
close(), mais unclose()explicite est déterministe et préférable dans les processus à longue durée d’exécution. - Les notifications de redémarrage sont journalisées au niveau
noticeavec le nombre de rendus — déclenche une alerte sur un taux de redémarrage élevé, qui signale des documents plus lourds que prévu.
Observabilité
Section intitulée « Observabilité »Injecte un logger PSR-3. Événements émis et niveaux associés :
| Événement | Niveau | Contexte |
|---|---|---|
| Début du rendu | debug | size, width, height |
| Rendu terminé | debug | pdfSize, contentHeight |
| Lancement du navigateur | info | binary |
| Redémarrage du navigateur | notice | count |
| Fermeture du navigateur | debug | renderCount |
Aucun HTML, octet PDF ni texte extrait n’est journalisé, conformément aux recommandations NIST SP 800-92 qui visent à maintenir les charges utiles hors des logs opérationnels. Construis des SLO de latence à partir de la paire start/complete et une alerte de taux de redémarrage à partir des événements notice.
Schémas de déploiement
Section intitulée « Schémas de déploiement »- Chrome en sidecar : exécute Chrome dans le même conteneur que le worker PHP ; épingle
chrome_binary. Provisionne un conteneur compatible avec le sandbox — voir /integrations/artisan/chrome-renderer-setup/. - Sans conteneur / CLI : Artisan n’a pas de conteneur d’injection de dépendances. Utilise
EInvoiceServiceFactorypour les contrats de facture électronique Premium dans les runners CLI ; voir /integrations/artisan/boot-and-discovery/. - Bornage des ressources : associe
render_timeoutà un budget de requête en amont et à un cgroup/ulimit hôte. Consulte le modèle de menace sur /integrations/artisan/security-and-operations/.
Cas limites & pièges
Section intitulée « Cas limites & pièges »- Un renderer interrompu en plein rendu ferme tout de même la page Chrome (
finally) ; le pool reste utilisable. - Réutiliser un même renderer entre threads/processes n’est pas pris en charge ; un renderer possède un seul processus Chrome.
- Le redémarrage tous les 100 rendus est fixe ; dimensionne tes lots en conséquence pour des pics de latence prévisibles.
Performances
Section intitulée « Performances »En régime stable, le coût vient de la mise en page Chrome de l’entrée plus printToPDF, pas du surcoût du pont. Le coût de démarrage est amorti par keepAlive. Attends-toi à un pic de latence à chaque centième rendu (redémarrage du processus) — fais-le apparaître dans tes SLO plutôt que de le traiter comme un incident.
Notes de sécurité
Section intitulée « Notes de sécurité »C’est par les chemins de production qu’arrive le HTML non fiable. Relis /integrations/artisan/security-and-operations/. Les barrières réseau restent en place quelle que soit la configuration, mais no_sandbox: true supprime l’isolation du processus Chrome et renforce l’exigence de confiance envers l’entrée.
Contexte commercial
Section intitulée « Contexte commercial »Dans les workers sans conteneur, EInvoiceServiceFactory renvoie null quand Premium n’est pas installé, donc le chemin de rendu open-source continue de s’exécuter sans changement ; installe Pro/Enterprise pour activer l’intégration et la validation de facture électronique sur le document rendu.
Voir aussi
Section intitulée « Voir aussi »- /integrations/artisan/quickstart/
- /integrations/artisan/configuration/
- /integrations/artisan/security-and-operations/
- /integrations/artisan/chrome-renderer-setup/
- /integrations/artisan/troubleshooting/