Przejdź do głównej zawartości

Artisan w środowisku produkcyjnym

W środowisku produkcyjnym wstrzykuj skonfigurowany renderer oraz rejestrator zgodny z PHP Standards Recommendation 3 (PSR-3), ponownie wykorzystuj działający proces Chrome między renderowaniami, ustawiaj jawne wysokości dla dokumentów wieloelementowych i obejmuj ścieżkę renderowania nadrzędnym limitem czasu.

Klasa BrowserPool utrzymuje przy życiu jeden proces Chrome (keepAlive: true) i uruchamia go ponownie co 100 renderowań, aby ograniczyć narastanie zużycia pamięci — znany wzorzec w długo działających klientach Chrome DevTools Protocol (CDP). W procesie renderującym wiele dokumentów używaj jednego długo działającego renderera zamiast osobnego renderera dla każdego żądania, aby koszt uruchomienia Chrome ponosić tylko sporadycznie.

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

Utwórz renderer raz, a potem używaj go ponownie. Wywołaj close() podczas zamykania procesu roboczego, aby deterministycznie zwolnić proces Chrome, zamiast czekać na destruktor. Dwa bloki catch rozdzielają błąd wdrożenia (brak środowiska uruchomieniowego) od błędu czasu renderowania (możliwego do ponowienia). Nie używaj pustych bloków catch.

Zarejestruj go w kontenerze jako singleton:

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

Gdy pominiesz wysokość, most mierzy wysokość treści w Chrome (max wysokości przewijania i przesunięcia dla body/document), przelicza ją na punkty i dodaje bufor bezpieczeństwa wynoszący ~0,2 cala (~14,4 pt). Bufor kompensuje różnicę między układem widoku Chrome a przepływem układu wydruku. Bez niego printToPDF może przenieść część treści na drugą stronę, którą PageImporter (tylko strona 0) by przyciął. Most wymusza minimalną wysokość strony wynoszącą 0,1 cala. Potwierdzają to testy ChromeHtmlRendererTest::renderUsesAutoFitHeightByDefault, ::renderAutoFitBufferIsAddedNotSubtracted oraz ::renderAppliesMinimumHeightOf0Point1InchForTinyExplicitHeight.

Dla dokumentów o stałym układzie (faktury, certyfikaty) przekaż jawną wysokość w punktach. Gdy wysokość jest jawna, nie jest dodawany żaden bufor, a wynik dokładnie odpowiada żądanemu rozmiarowi strony (co potwierdza test ::renderHonorsExplicitHeightWithoutAutoBuffer).

  • Utwórz jeden renderer na proces roboczy i używaj go ponownie. BrowserPool korzysta z działającej przeglądarki i automatycznie uruchamia ją ponownie na granicy 100 renderowań.
  • Wywołaj close() przy zamykaniu procesu roboczego oraz między dużymi partiami, gdy chcesz uzyskać świeży proces Chrome wcześniej niż na granicy 100 renderowań.
  • Destruktor wywołuje close(), ale jawne close() jest deterministyczne i preferowane w procesach długo działających.
  • Powiadomienia o ponownym uruchomieniu są zapisywane na poziomie notice wraz z liczbą renderowań; ustaw alert na podwyższoną częstość ponownych uruchomień, ponieważ wskazuje ona na dokumenty cięższe niż oczekiwano.

Wstrzyknij rejestrator PSR-3. Renderer emituje następujące zdarzenia i poziomy:

ZdarzeniePoziomKontekst
Początek renderowaniadebugsize, width, height
Renderowanie zakończonedebugpdfSize, contentHeight
Uruchomienie przeglądarkiinfobinary
Ponowne uruchomienie przeglądarkinoticecount
Zamknięcie przeglądarkidebugrenderCount

Nie są rejestrowane żadne dane HTML, bajty PDF ani wyodrębniony tekst. Dzięki temu ładunki danych nie trafiają do dzienników operacyjnych, co jest zgodne z wytycznymi dotyczącymi zawartości dzienników z publikacji National Institute of Standards and Technology Special Publication (NIST SP) 800-92. Zdefiniuj cele poziomu usług (SLO) dla opóźnień na podstawie pary zdarzeń start/complete oraz utwórz alert dla częstości ponownych uruchomień na podstawie zdarzeń notice.

  • Chrome jako sidecar: uruchom Chrome w tym samym kontenerze co proces roboczy PHP; przypnij chrome_binary. Przygotuj kontener obsługujący piaskownicę; zobacz /integrations/artisan/chrome-renderer-setup/.
  • Bez kontenera / CLI: Artisan nie ma kontenera wstrzykiwania zależności. W środowiskach uruchomieniowych interfejsu wiersza poleceń (CLI) użyj EInvoiceServiceFactory dla kontraktów e-faktur w wersji Premium; zobacz /integrations/artisan/boot-and-discovery/.
  • Ograniczanie zasobów: połącz render_timeout z nadrzędnym budżetem żądań oraz mechanizmami hosta cgroup/ulimit. Zapoznaj się z modelem zagrożeń na /integrations/artisan/security-and-operations/.
  • Renderer przerwany w trakcie renderowania nadal zamyka stronę Chrome (finally), a pula pozostaje zdatna do użytku.
  • Ponowne wykorzystanie jednego renderera między różnymi wątkami/procesami (threads/processes) nie jest obsługiwane; jeden renderer jest właścicielem jednego procesu Chrome.
  • Ponowne uruchomienie co 100 renderowań jest stałe; dobieraj rozmiar partii z myślą o nim, aby skoki opóźnień pozostawały przewidywalne.

W stanie ustalonym główny koszt to zbudowanie układu danych wejściowych w Chrome plus printToPDF, a nie narzut mostu. keepAlive rozkłada koszt uruchomienia na kolejne renderowania. Spodziewaj się skoku opóźnień przy co setnym renderowaniu (ponowne uruchomienie procesu); uwzględnij go w SLO zamiast traktować jako incydent.

Do ścieżek produkcyjnych trafia niezaufany kod HTML. Przeczytaj ponownie /integrations/artisan/security-and-operations/. Bariery sieciowe obowiązują niezależnie od konfiguracji, ale no_sandbox: true usuwa izolację procesu Chrome i zwiększa wymagany poziom zaufania do danych wejściowych.

W procesach roboczych bez kontenera EInvoiceServiceFactory zwraca null, gdy wersja Premium nie jest zainstalowana, dzięki czemu ścieżka renderowania open source działa bez zmian. Zainstaluj wersję Pro/Enterprise, aby włączyć osadzanie i walidację e-faktur w renderowanym dokumencie.

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