NextPDF Symfony in produzione
In breve
Sezione intitolata “In breve”Il bundle è progettato per runtime PHP a lunga esecuzione. I documenti non vengono condivisi, il registro dei font viene bloccato dopo il warmup e la cache delle immagini viene reimpostata tra una richiesta e l’altra. Usare lo streaming per i PDF di grandi dimensioni e delegare le operazioni onerose ai worker di Messenger.
Ciclo di vita dei servizi sicuro per i worker
Sezione intitolata “Ciclo di vita dei servizi sicuro per i worker”I runtime a lunga esecuzione mantengono attivo il container tra le richieste; di conseguenza, lo stato relativo alla singola richiesta non deve propagarsi. I worker di FrankenPHP, RoadRunner e Messenger seguono tutti questo modello. Il file services.php del bundle codifica il ciclo di vita riportato di seguito, verificato rispetto alle definizioni dei servizi:
- Document — non condiviso.
nextpdf.document(e gli aliasPdfDocumentInterface/Document) viene risolto ogni volta in una nuova istanza. In base a PSR-11, un container può legittimamente restituire un valore diverso a ogniget()per lo stesso id (PSR-11 §1.1.2). Risolvere un documento per ogni richiesta. Non conservarne mai uno tra una richiesta e l’altra. - FontRegistry — condiviso e bloccato. Il registro è un singleton con durata pari a quella del processo. Dopo
warmup()(quandopreload_fontsnon è vuoto) il compiler pass chiamalock(). Il blocco impedisce la mutazione a runtime e, quindi, la contaminazione dello stato dei font tra le richieste. - ImageRegistry — condiviso, reimpostato a ogni richiesta. La cache delle immagini con limite e politica least-recently-used (LRU) è condivisa, ma contrassegnata con il tag
kernel.resete il metodoreset, in modo che Symfony la svuoti tra le richieste con i runtime che rispettanokernel.reset. - Contratti EInvoice — non condivisi. Quando sono presenti le implementazioni Premium, i servizi embedder, validator, profile e schematron vengono registrati come non condivisi. Il contesto del parser relativo alla singola chiamata non si propaga mai tra una richiesta e l’altra.
Pattern di injection consigliato
Sezione intitolata “Pattern di injection consigliato”Iniettare PdfFactory — un contenitore di configurazione condiviso e privo di stato — e chiamare create() per ogni richiesta:
public function __construct(private readonly PdfFactory $pdf) {}
public function action(): Response{ $doc = $this->pdf->create(); // fresh, disposable // ... build ... return PdfResponse::inline($doc, 'document.pdf');}Non iniettare Document o nextpdf.document in un servizio a sua volta condiviso e mantenuto tra le richieste. Risolverlo invece all’interno del metodo con ambito di richiesta.
Streaming di documenti di grandi dimensioni
Sezione intitolata “Streaming di documenti di grandi dimensioni”PdfResponse::streamDownload() e streamInline() restituiscono una StreamedResponse. Il relativo callback emette il corpo del PDF in blocchi da 64 KB ed esegue il flush dopo ciascun blocco. In questo modo si limita il buffer della risposta per i documenti di grandi dimensioni. Entrambi i compromessi riportati di seguito sono verificati rispetto a PdfResponse:
- Le varianti in streaming omettono intenzionalmente
Content-Length(l’oggetto risposta non conosce in anticipo la dimensione del corpo). Le barre di avanzamento dei download e alcuni proxy funzionano meglio con una lunghezza nota. Utilizzare le versioni non in streamingdownload()oinline()quando il documento è abbastanza piccolo da poter essere tenuto in memoria ed è preferibile disporre di una lunghezza del contenuto. - Le varianti in streaming emettono gli stessi header di sicurezza e lo stesso
Cache-Control: private, max-age=0, must-revalidatedelle varianti con buffer.
Scegliere lo streaming per report di diversi megabyte ed esportazioni in batch. Scegliere le varianti con buffer per risposte di piccole dimensioni e sensibili alla latenza.
Generazione asincrona su larga scala
Sezione intitolata “Generazione asincrona su larga scala”Delegare la generazione a Messenger quando le richieste devono rispondere rapidamente o quando il rendering richiede molta CPU.
- Implementare
PdfBuilderInterfaceper ogni tipo di documento. - Registrare i builder in un
container.service_locatore collegarlo aGeneratePdfHandlercome suo$builderLocator. - Instradare
GeneratePdfMessageverso un transport durevole. - Eseguire i worker con durata di vita limitata.
Durata di vita limitata dei worker
Sezione intitolata “Durata di vita limitata dei worker”Riciclare i worker affinché una perdita di memoria in una dipendenza di terze parti non possa crescere senza limiti:
php bin/console messenger:consume async \ --limit=200 \ --memory-limit=256M \ --time-limit=3600Le chiavi di configurazione messenger.timeout e messenger.retries del bundle registrano il timeout e il budget di retry previsti per ogni messaggio. Applicare il comportamento corrispondente tramite la strategia di retry di Symfony e i flag dei worker.
Sicurezza del percorso di output nei worker
Sezione intitolata “Sicurezza del percorso di output nei worker”GeneratePdfMessage convalida il percorso di output al momento della costruzione. GeneratePdfHandler lo riconvalida poi in fase di esecuzione, prima di scrivere su disco. Questo controllo in due fasi è importante per il lavoro asincrono. Un messaggio può rimanere in coda tra l’invio e il consumo; pertanto, l’handler non si fida ciecamente del percorso accodato. Come difesa in profondità, limitare le autorizzazioni del filesystem dei worker alla directory di output prevista.
Osservabilità
Sezione intitolata “Osservabilità”I servizi FontRegistry e ImageRegistry accettano un Psr\Log\LoggerInterface facoltativo (associato con nullOnInvalid()). Quando l’applicazione fornisce un logger, i registri possono emettere informazioni diagnostiche tramite quel logger. Il logger è un collaboratore facoltativo e sostituibile in base al contratto del logger PSR-3 (PSR-3). Per la visibilità a livello di richiesta, registrare i log attorno a PdfFactory::create() e all’handler di Messenger nel codice dell’applicazione. Utilizzare messenger:consume -vv durante il triage degli incidenti.
Checklist per il deployment
Sezione intitolata “Checklist per il deployment”- Bloccare un’unica major di
nextpdf/corenelcomposer.jsondell’applicazione (il bundle accetta^3.0 || ^5.2). - Verificare che
ext-mbstringeext-zlibsiano abilitate nell’immagine PHP distribuita (in caso contrario, il bundle si arresta immediatamente all’avvio). - Pre-popolare
preload_fontscon i font utilizzati dai documenti, in modo che il registro venga scaldato e bloccato all’avvio anziché alla prima richiesta. - Impostare
cache_pathsu una posizione scrivibile e persistente se si fa affidamento su artefatti memorizzati nella cache tra un deployment e l’altro. In caso contrario, il valore predefinito%kernel.cache_dir%va bene. - Eseguire
php bin/console cache:warmupdurante il deployment, in modo che il container compilato (incluse le sonde delle estensioni facoltative) venga creato prima del traffico. - Utilizzare un transport Messenger durevole (non
sync) per il lavoro asincrono in produzione e riciclare i worker con--limit/--memory-limit/--time-limit.
Casi limite e insidie
Sezione intitolata “Casi limite e insidie”- Risposte in streaming dietro un proxy con buffering — un proxy che memorizza nel buffer l’intero corpo annulla il vantaggio in termini di memoria. Configurare il proxy affinché esegua lo streaming delle risposte PDF oppure utilizzare risposte con buffer in quel contesto.
kernel.resetnon rispettato — con un runtime che non chiamakernel.reset, la cache delle immagini resta limitata daimage_cache_mbma non viene svuotata tra le richieste; dimensionare il limite di conseguenza.- Conservare un documento tra le richieste — un
Documentcatturato da una richiesta precedente porterà con sé stato obsoleto. Risolverlo sempre per ogni richiesta tramitePdfFactory.
Conformità
Sezione intitolata “Conformità”Ogni riga è un’affermazione normativa formulata in questa pagina, ancorata a un reference_id completo di 64 cifre esadecimali proveniente dal corpus SDO ad accesso riservato. La provenienza, ovvero il manifest del corpus e il transport di recupero, è disponibile in _sidecars/rag-citations.yaml.
| Specifica | Clausola | reference_id | Affermazione |
|---|---|---|---|
| PSR-11 | psr_11_container#1.1.2.p3.b | Servizio non condiviso: valore distinto a ogni risoluzione | |
| PSR-3 | psr_3_logger#x3.p17 | Collaboratore logger facoltativo |
Vedere anche
Sezione intitolata “Vedere anche”- /integrations/symfony/configuration/ — ciclo di vita dei servizi e parametri.
- /integrations/symfony/security-and-operations/ — header delle risposte, convalida dei percorsi, gestione delle chiavi.
- /integrations/symfony/troubleshooting/ — diagnostica di avvio e runtime.
- /integrations/symfony/quickstart/ — configurazione asincrona minima.