Ga naar inhoud

NextPDF Symfony in productie

Gebruik de bundle in langlopende PHP-runtimes. De bundle maakt niet-gedeelde documenten aan, vergrendelt het lettertyperegister na de warmup en stelt de afbeeldingscache tussen verzoeken opnieuw in. Stream grote PDF-bestanden (Portable Document Format) en verplaats zware taken naar Messenger-workers.

Langlopende runtimes houden de container tussen verzoeken in leven; daarom moet verzoekgebonden status geïsoleerd blijven. FrankenPHP, RoadRunner en Messenger-workers volgen dit model. De services.php van de bundle definieert de onderstaande levenscyclus, geverifieerd aan de hand van de servicedefinities:

  • Document — niet-gedeeld. nextpdf.document (en de aliassen PdfDocumentInterface / Document) levert bij elke resolutie een nieuwe instantie op. Onder PSR-11 (PHP Standard Recommendation 11) mag een container legitiem een andere waarde teruggeven bij elke get() voor dezelfde id (PSR-11 §1.1.2). Resolve per verzoek een document. Houd het nooit tussen verzoeken vast.
  • FontRegistry — gedeeld en vergrendeld. Het register is een singleton voor de levensduur van het proces. Na warmup() (wanneer preload_fonts niet leeg is) roept de compiler pass lock() aan. De vergrendeling voorkomt mutatie tijdens runtime en vervuiling van de lettertypestatus tussen verzoeken.
  • ImageRegistry — gedeeld, opnieuw ingesteld per verzoek. De begrensde least recently used-afbeeldingscache (LRU) is gedeeld, maar is getagd met kernel.reset met methode reset, zodat Symfony hem tussen verzoeken wist onder runtimes die kernel.reset respecteren.
  • EInvoice-contracten — niet-gedeeld. Wanneer Premium-implementaties aanwezig zijn, worden de embedder-, validator-, profile- en schematron-services geregistreerd als niet-gedeeld. De parsercontext blijft beperkt tot de afzonderlijke aanroep en lekt nooit tussen verzoeken.

Injecteer PdfFactory als gedeelde, stateless configuratiehouder en roep create() per verzoek aan:

public function __construct(private readonly PdfFactory $pdf) {}
public function action(): Response
{
$doc = $this->pdf->create(); // fresh, disposable
// ... build ...
return PdfResponse::inline($doc, 'document.pdf');
}

Injecteer Document of nextpdf.document niet in een gedeelde service die tussen verzoeken wordt vastgehouden. Resolve het in plaats daarvan binnen de verzoekgebonden methode.

PdfResponse::streamDownload() en streamInline() retourneren een StreamedResponse. De callback verzendt de PDF-body in chunks van 64 KB en flusht na elke chunk, waardoor de responsebuffer voor grote documenten begrensd blijft. Het onderstaande gedrag is geverifieerd aan de hand van PdfResponse:

  • De gestreamde varianten laten Content-Length opzettelijk weg omdat het responseobject de bodygrootte niet vooraf kent. Voortgangsbalken voor downloads en sommige proxy’s werken beter met een bekende lengte. Gebruik het niet-gestreamde download() of inline() wanneer het document klein genoeg is om in het geheugen te houden en een contentlengte gewenst is.
  • De gestreamde varianten verzenden dezelfde beveiligingsheaders en dezelfde Cache-Control: private, max-age=0, must-revalidate als de gebufferde varianten.

Kies streaming voor rapporten van meerdere megabytes en batchexports. Kies de gebufferde varianten voor kleine responses die gevoelig zijn voor latency.

Verplaats de generatie naar Messenger wanneer verzoeken snel moeten worden afgehandeld of wanneer het renderen processorintensief is.

  1. Implementeer PdfBuilderInterface voor elk documenttype.
  2. Registreer builders in een container.service_locator en koppel die als de $builderLocator van GeneratePdfHandler.
  3. Routeer GeneratePdfMessage naar een duurzaam transport.
  4. Draai workers met begrensde levensduren.

Recycle workers zodat een gelekte allocatie in een afhankelijkheid van derden niet onbeperkt kan blijven groeien:

Terminal window
php bin/console messenger:consume async \
--limit=200 \
--memory-limit=256M \
--time-limit=3600

De configuratiesleutels messenger.timeout en messenger.retries van de bundle leggen de beoogde timeout per bericht en het herhaalbudget vast. Dwing hetzelfde gedrag af met de retry-strategie en de worker-flags van Symfony.

GeneratePdfMessage valideert het uitvoerpad tijdens de constructie. GeneratePdfHandler valideert het opnieuw tijdens de uitvoering, voordat naar schijf wordt geschreven. Deze controle in twee fasen is belangrijk voor asynchroon werk. Een bericht kan tussen verzending en consumptie in een wachtrij blijven staan, dus de handler vertrouwt het pad uit de wachtrij niet blindelings. Beperk de bestandssysteemrechten van de worker tot de beoogde uitvoermap als verdediging in de diepte.

De services FontRegistry en ImageRegistry accepteren een optionele Psr\Log\LoggerInterface (gebonden met nullOnInvalid()). Wanneer de applicatie een logger levert, kunnen de registers diagnostiek via die logger uitsturen. De logger is een optionele, verwisselbare collaborator onder het PSR-3 logger-contract (PSR-3). Voor zichtbaarheid op verzoekniveau log je rondom PdfFactory::create() en de Messenger-handler in je applicatiecode. Gebruik messenger:consume -vv tijdens incidenttriage.

  • Pin één nextpdf/core-major in de composer.json van de applicatie (de bundle accepteert ^3.0 || ^5.2).
  • Zorg ervoor dat ext-mbstring en ext-zlib zijn ingeschakeld in de gedeployde PHP-image (anders faalt de bundle snel bij het opstarten).
  • Vul preload_fonts vooraf met de lettertypen die je documenten gebruiken, zodat het register bij het opstarten opwarmt en wordt vergrendeld in plaats van bij het eerste verzoek.
  • Wijs cache_path aan naar een schrijfbare, persistente locatie als je tussen deploys op gecachete artefacten vertrouwt. Anders volstaat de standaardwaarde %kernel.cache_dir%.
  • Draai php bin/console cache:warmup tijdens de deploy zodat de gecompileerde container (inclusief de probes voor optionele extensies) wordt opgebouwd voordat er verkeer binnenkomt.
  • Gebruik een duurzaam Messenger-transport (niet sync) voor asynchroon werk in productie, en recycle workers met --limit / --memory-limit / --time-limit.
  • Gestreamde responses achter een bufferende proxy — Een proxy die de volledige body buffert, doet het geheugenvoordeel teniet. Configureer de proxy om PDF-responses te streamen, of gebruik in dat geval gebufferde responses.
  • kernel.reset niet gerespecteerd — Onder een runtime die kernel.reset niet aanroept, wordt de afbeeldingscache begrensd door image_cache_mb maar niet tussen verzoeken gewist; stem de limiet daarop af.
  • Een document over verzoeken heen vasthouden — Een vastgehouden Document uit een eerder verzoek draagt verouderde status met zich mee. Resolve altijd per verzoek via PdfFactory.

Elke rij bevat een normatieve bewering op deze pagina, gekoppeld aan een volledige 64-hex reference_id uit het afgeschermde corpus van de standards development organization (SDO). De herkomst van het corpusmanifest en het ophaaltransport staat in _sidecars/rag-citations.yaml.

SpecClausulereference_idBewering
PSR-11psr_11_container#1.1.2.p3.bNiet-gedeelde service: aparte waarde per resolutie
PSR-3psr_3_logger#x3.p17Optionele logger-collaborator
  • /integrations/symfony/configuration/ — levenscyclus van services en parameters.
  • /integrations/symfony/security-and-operations/ — responseheaders, padvalidatie, sleutelbeheer.
  • /integrations/symfony/troubleshooting/ — diagnostiek bij opstarten en tijdens runtime.
  • /integrations/symfony/quickstart/ — de minimale asynchrone setup.