NextPDF Symfony in productie
In het kort
Sectie met titel “In het kort”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.
Worker-veilige levenscyclus van services
Sectie met titel “Worker-veilige levenscyclus van services”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 aliassenPdfDocumentInterface/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 elkeget()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()(wanneerpreload_fontsniet leeg is) roept de compiler passlock()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.resetmet methodereset, zodat Symfony hem tussen verzoeken wist onder runtimes diekernel.resetrespecteren. - 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.
Aanbevolen injectiepatroon
Sectie met titel “Aanbevolen injectiepatroon”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.
Grote documenten streamen
Sectie met titel “Grote documenten streamen”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-Lengthopzettelijk 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-gestreamdedownload()ofinline()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-revalidateals de gebufferde varianten.
Kies streaming voor rapporten van meerdere megabytes en batchexports. Kies de gebufferde varianten voor kleine responses die gevoelig zijn voor latency.
Asynchrone generatie op schaal
Sectie met titel “Asynchrone generatie op schaal”Verplaats de generatie naar Messenger wanneer verzoeken snel moeten worden afgehandeld of wanneer het renderen processorintensief is.
- Implementeer
PdfBuilderInterfacevoor elk documenttype. - Registreer builders in een
container.service_locatoren koppel die als de$builderLocatorvanGeneratePdfHandler. - Routeer
GeneratePdfMessagenaar een duurzaam transport. - Draai workers met begrensde levensduren.
Begrensde levensduur van workers
Sectie met titel “Begrensde levensduur van workers”Recycle workers zodat een gelekte allocatie in een afhankelijkheid van derden niet onbeperkt kan blijven groeien:
php bin/console messenger:consume async \ --limit=200 \ --memory-limit=256M \ --time-limit=3600De 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.
Veiligheid van het uitvoerpad in workers
Sectie met titel “Veiligheid van het uitvoerpad in workers”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.
Observeerbaarheid
Sectie met titel “Observeerbaarheid”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.
Deploymentchecklist
Sectie met titel “Deploymentchecklist”- Pin één
nextpdf/core-major in decomposer.jsonvan de applicatie (de bundle accepteert^3.0 || ^5.2). - Zorg ervoor dat
ext-mbstringenext-zlibzijn ingeschakeld in de gedeployde PHP-image (anders faalt de bundle snel bij het opstarten). - Vul
preload_fontsvooraf 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_pathaan 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:warmuptijdens 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.
Randgevallen en valkuilen
Sectie met titel “Randgevallen en valkuilen”- 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.resetniet gerespecteerd — Onder een runtime diekernel.resetniet aanroept, wordt de afbeeldingscache begrensd doorimage_cache_mbmaar niet tussen verzoeken gewist; stem de limiet daarop af.- Een document over verzoeken heen vasthouden — Een vastgehouden
Documentuit een eerder verzoek draagt verouderde status met zich mee. Resolve altijd per verzoek viaPdfFactory.
Conformiteit
Sectie met titel “Conformiteit”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.
| Spec | Clausule | reference_id | Bewering |
|---|---|---|---|
| PSR-11 | psr_11_container#1.1.2.p3.b | Niet-gedeelde service: aparte waarde per resolutie | |
| PSR-3 | psr_3_logger#x3.p17 | Optionele logger-collaborator |
Zie ook
Sectie met titel “Zie ook”- /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.