Generación de documentos de alto volumen
Spec: ISO 24495-1:2023, §5 ISO 24495-1:2023 §5 Spec: ISO 9241-112:2025, §6.1.2.3 ISO 9241-112:2025 §6.1.2.3 Evidence: Benchmark-backed
En resumen
Sección titulada «En resumen»Generar un PDF es llamar a una función. Generar cien mil de forma programada es un problema de sistemas: memoria que debe mantenerse acotada, trabajo que debe paralelizarse y cifras que deben significar algo. Esta página recorre el escenario de generación por lotes, desde el problema de rendimiento hasta un despliegue capaz de resistir la carga. Deja claro que la respuesta honesta es «medirlo con los propios documentos», no una cifra de titular.
Por qué esto importa
Sección titulada «Por qué esto importa»La generación por lotes suele fallar de dos formas características. La primera es el crecimiento progresivo de la memoria. Un proceso de trabajo de larga duración acumula estado retenido, documento tras documento, hasta que agota la memoria a mitad del lote; la ejecución no queda ni completa ni fallida de forma limpia. La segunda es una cifra aparentemente segura, pero sin significado operativo: se usa una prueba de rendimiento de un documento trivial para dimensionar una flota que representa documentos complejos, y solo bajo carga de producción se descubre que era incorrecta.
Ambas se pueden evitar, pero solo si desde el principio se diseñan la forma de la memoria y el método de medición, en lugar de añadirlos tras el primer incidente.
La versión breve
Sección titulada «La versión breve»- La unidad de trabajo es un documento desechable, no uno compartido. Mantener los datos de duración del proceso (fuentes, caché de imágenes) en registros compartidos; crear y descartar el documento en cada representación.
- La memoria tiene dos partes, y solo una importa para un proceso de trabajo de larga duración. El pico transitorio durante una representación es esperado; la memoria retenida que no vuelve es la fuga que acaba con un lote.
- El rendimiento es paralelismo más un coste por representación acotado. La forma que resiste es una cola que alimenta procesos de trabajo sin estado, cada uno dedicado a representar y liberar.
- Una cifra sin su método no es una cifra. NextPDF informa de las mediciones por representación como datos que se recopilan, y rechaza las afirmaciones de velocidad sin matices. La cifra más importante es la que se mide con las propias plantillas (ISO 24495-1 §5.x11: el mensaje importante debe quedar donde el lector lo encuentre).
Cómo lo aborda NextPDF
Sección titulada «Cómo lo aborda NextPDF»La arquitectura se construye en torno a una única decisión: el estado que vive durante el proceso es compartido e inmutable; el estado que vive durante una representación es nuevo y se desecha. Las fuentes son datos estructurales que se analizan una sola vez y luego se bloquean, de modo que ninguna representación pueda mutarlas ni contaminar la siguiente. La caché de imágenes es un almacén acotado de tipo «el menos usado recientemente» que nunca se bloquea, de modo que la memoria se mantiene limitada sin fugarse entre solicitudes. La fábrica de documentos es un singleton sin estado; todo documento que crea es desechable.
Esa separación hace seguro ejecutar un proceso de trabajo durante horas bajo Octane, RoadRunner o Swoole. Elimina por construcción el modo de fallo en el que «la solicitud N corrompe la solicitud N+1», en lugar de confiar en que el documento se reinicie por sí mismo.
El escenario tiene cuatro etapas.
- Warm the shared state once On worker boot, parse and lock the font registry and size the image cache. This cost is paid once, not per document.
- Enqueue the work A queue holds the render jobs. The queue is the throughput dial — workers scale horizontally behind it.
- Render on a disposable document Each worker creates a fresh document from the factory, renders, emits the bytes, and lets the document go.
- Measure, then size Collect per-render time and peak memory. Size the fleet from measurements on your own templates, not a generic figure.
Los puentes de framework hacen que esta forma sea la predeterminada, no algo que haya que ensamblar a mano. El proveedor de servicios de Laravel registra el registro de fuentes como un singleton precalentado y bloqueado, y enlaza el documento como una instancia nueva por cada resolución. Incluye un trabajo en cola con un número de intentos acotado, un tiempo de espera y un retroceso exponencial. Ese trabajo valida su ruta de salida en el lado del proceso de trabajo, porque una carga útil de cola serializada puede manipularse en tránsito. Las integraciones de Symfony y CodeIgniter siguen la misma disciplina de documento desechable y registro compartido.
Qué dice la evidencia
Sección titulada «Qué dice la evidencia»El modelo de memoria está respaldado por código. Evidence: Code-backed El NextPdfServiceProvider de Laravel registra el FontRegistry como un singleton que se precalienta y luego se bloquea mediante lock(), el ImageRegistry como un singleton de LRU acotado que deliberadamente no se bloquea, y el Document como un enlace por resolución a través de una fábrica sin estado. El modelo de documento desechable está en el cableado, no en la prosa. El GeneratePdfJob define tries, timeout y backoff, y revalida su ruta de salida dentro de handle().
La superficie de medición está respaldada por pruebas de rendimiento.
Evidence: Benchmark-backed El motor emite un
RenderReport inmutable por cada generación que contiene el tiempo de representación en milisegundos, el
pico de memoria en bytes, el número de páginas, los recuentos de advertencias y las apariciones de mecanismos de reserva: las
entradas exactas necesarias para dimensionar una flota. Un analizador de fragmentación de memoria
independiente distingue el pico (transitorio) de la memoria retenida. Esa
distinción permite saber si un proceso de trabajo de larga duración está sano o
tiene fugas lentas. El propio banco de pruebas está configurado para
repetir ciclos con precalentamiento, porque una sola medición de tiempo es ruido.
La disciplina es un principio de diseño: Evidence: Design principle NextPDF informa del rendimiento junto con su método y rechaza las afirmaciones de velocidad sin matices. Eso es coherente con la forma en que está escrita esta documentación: Spec: ISO 24495-1:2023, §5 ISO 24495-1:2023 §5 coloca el mensaje que importa donde el lector lo encontrará. El mensaje que importa aquí es «medir la propia carga de trabajo».
Ejemplo práctico
Sección titulada «Ejemplo práctico»El código siguiente muestra el bucle de documento desechable con medición e ilustra el modelo. El motor produce el RenderReport. La cola pertenece a la infraestructura de despliegue.
<?php
declare(strict_types=1);
use NextPDF\Contracts\DocumentFactoryInterface;use NextPDF\Observability\RenderReport;use Psr\Log\LoggerInterface;
/** * One batch worker iteration: render, emit, release, measure. * * The factory and its registries are process-lifetime singletons; the * document is disposable. Retained memory must return to baseline between * iterations or the worker is leaking. * * @param iterable<int, callable(\NextPDF\Core\Document): \NextPDF\Core\Document> $jobs */function runBatch( DocumentFactoryInterface $factory, LoggerInterface $logger, iterable $jobs,): void { foreach ($jobs as $jobId => $build) { $startedAt = hrtime(true);
// Fresh, disposable document — shares the warmed registries. $doc = $factory->create(); $doc = $build($doc); $bytes = $doc->getPdfData();
// Hand the bytes off to your sink (object store, response, etc.). unset($doc, $bytes); // let the per-render state go
$elapsedMs = (hrtime(true) - $startedAt) / 1_000_000;
$logger->info('pdf.render.complete', [ 'job_id' => $jobId, 'render_time_ms' => round($elapsedMs, 2), 'peak_memory_mb' => round(memory_get_peak_usage(true) / 1_048_576, 2), ]); }}El unset() no es cosmético. El estado por representación está diseñado para liberarse en cada iteración, de modo que la memoria retenida vuelva al valor de referencia. Un proceso de trabajo cuyo valor de referencia aumenta a lo largo de las iteraciones es el fallo que este bucle está diseñado para evitar.
Concepto erróneo habitual
Sección titulada «Concepto erróneo habitual»El concepto erróneo principal es «¿cuántos PDF por segundo puede generar NextPDF?», como si tuviera una sola respuesta. No la tiene; citar una es una forma de dimensionar mal las flotas. El coste de representación está dominado por el documento, así que la única cifra que vale la pena utilizar es la que se mide con las propias plantillas mediante el informe por representación del propio motor. Una cifra sin el documento, el hardware y el método que la respaldan es decoración, no datos.
El segundo concepto erróneo es que el pico de memoria es lo que se debe vigilar. El pico es transitorio y esperado: vuelve. La cifra que termina un lote es la memoria retenida que no vuelve. Precisamente por eso el motor separa ambas.
Límites y fronteras
Sección titulada «Límites y fronteras»- No existe una cifra de rendimiento universal, y esta página deliberadamente no indica ninguna. El coste de representación depende de los documentos; debe medirse con el informe por representación.
- La memoria acotada depende de que se use el modelo de documento desechable. Mantener un documento a lo largo de muchas representaciones, o compartir estado mutable por representación, revierte la garantía. Los puentes de framework adoptan por defecto la forma segura. El cableado hecho a mano debe replicarla.
- La caché de imágenes es acotada, no ilimitada. Bajo cargas de trabajo intensas con imágenes únicas, la LRU expulsa elementos. Ese es el diseño, no una regresión.
- El dimensionamiento del grupo de procesos de trabajo, la elección de la cola y el autoescalado son decisiones de despliegue ajenas al motor. NextPDF proporciona las mediciones y la primitiva acotada. No ejecuta la cola.
RenderReportaporta datos, no un veredicto. Indica qué ocurrió en una representación. Convertir eso en un plan de capacidad es parte del análisis.- Esta página está respaldada por pruebas de rendimiento en cuanto a la superficie de medición y respaldada por código en cuanto al modelo de memoria. No afirma ninguna tasa concreta.
| Edition | Availability |
|---|---|
| Core | El modelo de documento desechable, los registros compartidos inmutables, el
|
| Pro | Las mismas primitivas; las funciones comerciales (firma, PDF/A) añaden un coste por representación que hay que medir, no suponer. |
| Enterprise | Las mismas primitivas; el trabajo de facturas estructuradas y validación añade un coste por representación adicional que escala con el tamaño de la carga útil y del conjunto de reglas. |
Documentos relacionados
Sección titulada «Documentos relacionados»- Memoria y streaming: cómo el motor mantiene acotada la memoria en documentos grandes y en qué puntos transmite por streaming.
- Pruebas de rendimiento honestas: qué valor tiene una cifra de prueba de rendimiento sin su método, y cómo NextPDF informa del rendimiento.
- Operar NextPDF en producción: convertir los informes por representación en señales de salud cuando el lote se ejecuta realmente.
Glosario
Sección titulada «Glosario»- Documento desechable: una instancia de documento creada para una sola representación y descartada después, de modo que ningún estado se filtre a la siguiente representación.
- Registro compartido: estado de duración del proceso, inmutable tras el precalentamiento (fuentes, caché de imágenes), reutilizado entre representaciones sin coste por representación.
- Pico de memoria: la marca máxima transitoria durante una representación; es esperada y vuelve al valor de referencia.
- Memoria retenida: memoria todavía retenida después de que termina una representación; un valor de referencia de memoria retenida que sube entre representaciones es una fuga.
- Proceso de trabajo: un proceso de larga duración que extrae trabajos de representación de una cola; debe permanecer acotado en memoria para sobrevivir a un lote.
- RenderReport: la instantánea inmutable de métricas por representación del motor (tiempo, pico de memoria, número de páginas, advertencias) que se usa para dimensionar la capacidad a partir de datos reales.