Lewati ke konten

Artisan di lingkungan produksi

Di lingkungan produksi, injeksikan renderer yang sudah dikonfigurasi dan logger PHP Standards Recommendation 3 (PSR-3), gunakan ulang proses Chrome yang aktif antar-render, tetapkan tinggi eksplisit untuk dokumen multi-elemen, dan batasi jalur render dengan batas waktu di sisi hulu.

BrowserPool mempertahankan satu proses Chrome tetap aktif (keepAlive: true) dan memulai ulang proses tersebut setiap 100 render untuk membatasi pertumbuhan memori, yaitu pola akumulasi yang dikenal pada klien Chrome DevTools Protocol (CDP) berumur panjang. Untuk worker yang merender banyak dokumen, gunakan satu renderer berumur panjang alih-alih satu renderer per permintaan, sehingga biaya startup Chrome jarang ditanggung.

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

Buat renderer satu kali, lalu gunakan kembali. Panggil close() saat worker dimatikan untuk melepaskan proses Chrome secara deterministik alih-alih menunggu destructor. Kedua cabang catch memisahkan kegagalan deployment (runtime tidak tersedia) dari kegagalan saat render (dapat dicoba ulang). Jangan gunakan blok catch kosong.

Daftarkan di dalam container sebagai singleton:

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

Saat Anda tidak menyertakan tinggi, jembatan mengukur tinggi konten di Chrome (max dari tinggi scroll dan offset body/document), mengonversinya menjadi poin, lalu menambahkan buffer keamanan sekitar 0,2 inci (~14,4 pt). Buffer ini mengompensasi selisih antara tata letak viewport Chrome dan reflow tata letak cetaknya. Tanpa buffer ini, printToPDF dapat membuat konten meluber ke halaman kedua yang akan dipotong oleh PageImporter (hanya halaman 0). Jembatan menerapkan tinggi kertas minimum sebesar 0,1 inci. Pengujian ChromeHtmlRendererTest::renderUsesAutoFitHeightByDefault, ::renderAutoFitBufferIsAddedNotSubtracted, dan ::renderAppliesMinimumHeightOf0Point1InchForTinyExplicitHeight memverifikasi perilaku ini.

Untuk dokumen dengan tata letak tetap (faktur, sertifikat), berikan tinggi eksplisit dalam satuan poin. Jika tinggi diberikan secara eksplisit, tidak ada buffer yang ditambahkan, dan keluarannya sama persis dengan ukuran kertas yang diminta (diverifikasi oleh ::renderHonorsExplicitHeightWithoutAutoBuffer).

  • Buat satu renderer per worker, lalu gunakan kembali. BrowserPool menggunakan kembali peramban yang aktif dan otomatis memulai ulang saat mencapai batas 100 render.
  • Panggil close() saat worker dimatikan dan di antara batch besar jika Anda menginginkan proses Chrome yang baru sebelum batas 100 render.
  • Destructor memanggil close(), tetapi memanggil close() secara eksplisit bersifat deterministik dan lebih disarankan dalam proses yang berjalan lama.
  • Pemberitahuan restart dicatat pada level notice beserta jumlah render; siapkan peringatan untuk laju restart yang meningkat, karena hal itu menandakan dokumen lebih berat daripada yang diperkirakan.

Injeksikan logger PSR-3. Renderer memancarkan event dan level berikut:

EventLevelKonteks
Mulai renderdebugsize, width, height
Render selesaidebugpdfSize, contentHeight
Peluncuran perambaninfobinary
Restart perambannoticecount
Penutupan perambandebugrenderCount

Tidak ada HTML, bita PDF, ataupun teks hasil ekstraksi yang dicatat. Hal ini menjaga payload tetap berada di luar log operasional dan selaras dengan panduan isi log National Institute of Standards and Technology Special Publication (NIST SP) 800-92. Buat service-level objective (SLO) latensi berdasarkan pasangan start/complete, dan siapkan peringatan laju restart dari event notice.

  • Sidecar Chrome: jalankan Chrome di container yang sama dengan worker PHP; sematkan chrome_binary. Sediakan container yang mendukung sandbox; lihat /integrations/artisan/chrome-renderer-setup/.
  • Tanpa container / CLI: Artisan tidak menyediakan container dependency injection. Gunakan EInvoiceServiceFactory untuk kontrak e-invoice Premium pada runner command-line interface (CLI); lihat /integrations/artisan/boot-and-discovery/.
  • Pembatasan sumber daya: pasangkan render_timeout dengan anggaran permintaan di sisi hulu serta cgroup/ulimit host. Lihat model ancaman di /integrations/artisan/security-and-operations/.
  • Renderer yang terhenti saat proses render berlangsung tetap menutup halaman Chrome (finally), dan pool tetap dapat digunakan.
  • Penggunaan ulang satu renderer di seluruh threads/processes tidak didukung; satu renderer memiliki satu proses Chrome.
  • Restart pada 100 render bersifat tetap; tentukan ukuran batch dengan mempertimbangkan hal ini agar lonjakan latensi tetap dapat diprediksi.

Biaya pada kondisi stabil adalah tata letak Chrome untuk input ditambah printToPDF, bukan overhead jembatan. keepAlive menyebarkan biaya startup ke seluruh render. Perkirakan adanya lonjakan latensi pada setiap render ke-100 (restart proses); perhitungkan hal itu dalam SLO alih-alih memperlakukannya sebagai insiden.

Jalur produksi menerima HTML yang tidak tepercaya. Baca ulang /integrations/artisan/security-and-operations/. Penghalang jaringan tetap berlaku apa pun konfigurasinya, tetapi no_sandbox: true menghapus isolasi proses Chrome dan meningkatkan tingkat kepercayaan yang disyaratkan terhadap input.

Pada worker tanpa container, EInvoiceServiceFactory mengembalikan null saat Premium tidak terpasang, sehingga jalur render open-source tetap berjalan tanpa perubahan. Pasang Pro/Enterprise untuk mengaktifkan penyematan dan validasi e-invoice pada dokumen yang telah dirender.

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