Ir al contenido
getnextpdf.com

Enterprise edición

Medición — Referencia detallada

El espacio de nombres NextPDF\Enterprise\Metering incorpora medición de uso a nivel de orquestación para visibilidad de facturación y auditoría. La superficie pública consta de seis símbolos: MeterCollector, MeterEntry, MeteringReporter, MeteringBackendInterface, PrometheusMeteringBackend y PrometheusPushgatewayException. El colector almacena entradas inmutables en memoria y las vacía por lotes. El reportador difunde cada lote hacia uno o varios backends con reintento y aislamiento de fallos por backend. La medición es de mejor esfuerzo y no fatal: una interrupción de un backend de medición degrada la observabilidad, nunca el procesamiento de documentos. Este flujo no es la fuente autoritativa para la aplicación de cuotas. Para la guía a nivel de flujo de trabajo, véase Medición.

Esta capacidad se incorpora en NextPDF Enterprise (nextpdf/enterprise) y se activa con un sobre de licencia de nivel Enterprise. Un despliegue sin esa titularidad no carga las clases de la capacidad. Comparar ediciones y obtener una licencia.

La medición es una capacidad base de Enterprise, disponible una vez instalado el paquete Enterprise; no existe un indicador separado por característica. NextPDF Core (Apache-2.0) y NextPDF Pro no tienen colector, reportador ni superficie de backend; el contrato se incorpora únicamente en nextpdf/enterprise.

SímboloParámetrosComportamiento por defectoDevuelveLanza o falla conNotas
MeterCollector::__constructMeteringReporter $reporter, int $bufferSize = 100Crea un colector con un búfer en memoria vacíoNuevo MeterCollectorNo lanza$bufferSize está documentado como positive-int
MeterCollector::recordstring $operation, int $count, string $tenantId, string $licenseId, int $pagesProcessed = 0, float $durationMs = 0.0, array $metadata = []Añade una MeterEntry inmutable marcada con la hora actual; se vacía automáticamente cuando el búfer alcanza $bufferSizevoidNo lanza; un vaciado automático delega en el reportador, que nunca lanzaLa marca temporal se toma en el momento del registro
MeterCollector::flushEntrega todas las entradas almacenadas al reportador; un búfer vacío es una operación nulavoidNo lanza; los fallos de backend son absorbidos por el reportadorEl búfer se intercambia antes de la entrega; seguro ante reentrada
MeterCollector::bufferCountDevuelve el número de entradas almacenadasint<0, max>No lanzaDiagnóstico y decisiones de contrapresión
MeterCollector::registerShutdownFlushRegistra flush() mediante register_shutdown_functionvoidNo lanzaLlamar una vez en el arranque en despliegues PHP-FPM
MeterEntry::__constructstring $operation, int $count, DateTimeImmutable $timestamp, string $tenantId, string $licenseId, int $pagesProcessed = 0, float $durationMs = 0.0, array $metadata = []Almacena los valores suministrados tal cualNuevo MeterEntrySin @throws declarado; PHP lanza TypeError ante tipos de argumento no coincidentes bajo strict_typesfinal readonly; las ocho propiedades promovidas son públicas
MeteringReporter::__constructlist<MeteringBackendInterface> $backends, int $maxRetries = 2, LoggerInterface $logger = new NullLogger()Valida y almacena la lista de backendsNuevo MeteringReporterInvalidArgumentException cuando $backends está vacía$maxRetries cuenta el total de intentos de entrega por backend
MeteringReporter::reportlist<MeterEntry> $entriesEntrega el lote a cada backend de forma independiente, con reintento por backendvoidNo lanza; los intentos agotados registran a nivel de error y descartan el lote de ese backendUna lista vacía es una operación nula
MeteringBackendInterface::reportlist<MeterEntry> $entriesEntrega un lote al backendvoidRuntimeException cuando el backend es inalcanzableLas implementaciones DEBEN ser idempotentes (deduplicar por timestamp + operation + tenantId)
MeteringBackendInterface::isHealthySonda de alcanzabilidadboolSin @throws declaradoSolo diagnóstico; el reportador no lo usa como control de acceso
MeteringBackendInterface::backendNameNombre de backend para diagnósticonon-empty-stringSin @throws declaradoPor ejemplo "prometheus", "billing-api", "null"
PrometheusMeteringBackend::__constructClientInterface $httpClient, RequestFactoryInterface $requestFactory, StreamFactoryInterface $streamFactory, string $pushgatewayUrl, string $jobName = 'nextpdf_metering'Configura un destino de push de PushgatewayNuevo PrometheusMeteringBackendNo lanzaSe inyectan el cliente PSR-18 y las factorías PSR-17
PrometheusMeteringBackend::reportlist<MeterEntry> $entriesAgrega el lote por serie de operación-y-tenant y hace POST del texto de exposición a <pushgatewayUrl>/metrics/job/<jobName>voidPrometheusPushgatewayException ante un estado distinto de 2xx o un fallo de transporte PSR-18Una lista vacía es una operación nula
PrometheusMeteringBackend::isHealthySondea el endpoint de salud de Pushgateway; true solo con HTTP 200boolNo lanza; cualquier fallo devuelve falseSonda GET de solo lectura
PrometheusMeteringBackend::backendNameDevuelve "prometheus"non-empty-stringNo lanzaConstante
PrometheusPushgatewayExceptionSeñala una entrega de Pushgateway fallidaEs el lanzablefinal; extiende RuntimeException
public function __construct(
private readonly MeteringReporter $reporter,
private readonly int $bufferSize = 100,
) {}
public function record(
string $operation,
int $count,
string $tenantId,
string $licenseId,
int $pagesProcessed = 0,
float $durationMs = 0.0,
array $metadata = [],
): void
public function flush(): void
public function bufferCount(): int
public function registerShutdownFlush(): void
public function __construct(
public string $operation,
public int $count,
public DateTimeImmutable $timestamp,
public string $tenantId,
public string $licenseId,
public int $pagesProcessed = 0,
public float $durationMs = 0.0,
public array $metadata = [],
) {}
public function report(array $entries): void;
public function isHealthy(): bool;
public function backendName(): string;
public function __construct(
array $backends,
private readonly int $maxRetries = 2,
private readonly LoggerInterface $logger = new NullLogger(),
)
public function report(array $entries): void
public function __construct(
private readonly ClientInterface $httpClient,
private readonly RequestFactoryInterface $requestFactory,
private readonly StreamFactoryInterface $streamFactory,
private readonly string $pushgatewayUrl,
private readonly string $jobName = self::DEFAULT_JOB_NAME,
) {}
final class PrometheusPushgatewayException extends RuntimeException {}

Propiedades públicas de solo lectura de MeterEntry

PropiedadTipoSignificado
$operationnon-empty-stringTipo de operación, por ejemplo "parse", "compress", "embed", "rag_query"
$countpositive-intNúmero de unidades consumidas
$timestampDateTimeImmutableCuándo ocurrió la operación; el colector la marca en el momento del registro
$tenantIdnon-empty-stringIdentificador del tenant
$licenseIdnon-empty-stringIdentificador de licencia
$pagesProcessedint<0, max>Páginas PDF procesadas; 0 para operaciones que no son PDF
$durationMsfloatDuración de la operación en milisegundos
$metadataarray<string, mixed>Metadatos de formato libre específicos de la operación
  • MeterCollector::record() construye una MeterEntry inmutable, la marca con la hora actual y la añade al búfer en memoria. Cuando el búfer alcanza $bufferSize entradas, el colector se vacía automáticamente.
  • flush() es idempotente y seguro ante reentrada. Un búfer vacío es una operación nula. El búfer se intercambia antes de entregar el lote al reportador, de modo que un vaciado reentrante no puede duplicar el envío.
  • MeteringReporter rechaza la construcción con una lista de backends vacía. Esa InvalidArgumentException es la única excepción en la ruta colector/reportador.
  • MeteringReporter::report() entrega cada lote a cada backend de forma independiente. Un backend que falla nunca impide que otro backend reciba el mismo lote.
  • $maxRetries cuenta el total de intentos de entrega por backend; el valor por defecto de 2 significa un intento inicial más un reintento. Cada intento fallido registra una advertencia con el nombre del backend, el número de intento y el recuento de entradas.
  • Cuando el intento final para un backend falla, el reportador registra además a nivel de error con el recuento de entradas descartadas, y luego continúa. Nunca lanza desde report(), por lo que quienes lo invocan no deben inferir la entrega a partir de un retorno normal.
  • Los backends DEBEN ser idempotentes. El contrato de la interfaz exige deduplicación basada en timestamp, operation y el identificador del tenant. El reportador en sí no deduplica.
  • PrometheusMeteringBackend::report() agrega el lote en series por operación y por tenant y hace POST de exposición de texto Prometheus a <pushgatewayUrl>/metrics/job/<jobName> con Content-Type text/plain; version=0.0.4. El nombre de trabajo por defecto es nextpdf_metering.
  • La carga útil enviada lleva tres contadores — nextpdf_operations_total, nextpdf_pages_processed_total y nextpdf_operation_duration_ms_total — cada uno etiquetado por operación y tenant.
  • Este flujo de medición no es autoritativo. La aplicación de cuotas y la medición autoritativa de cómputo consumen la cifra de uso autoritativa separada del despliegue, nunca este búfer. Una brecha en la medición de orquestación es una brecha de observabilidad, no una brecha de exactitud de facturación.
  • Lote duplicado o reproducido. Absorbido por la idempotencia del backend; el reportador no deduplica. No confíe en una entrega exactamente-una-vez.
  • Reintentos agotados. El lote de ese backend se descarta y se registra a nivel de error. Un retorno normal de report() o flush() nunca implica entrega.
  • Salida del proceso antes del vaciado. El búfer está únicamente en memoria. Un fallo, o una salida sin un manejador de apagado registrado, pierde las entradas almacenadas.
  • Desajuste del modelo de workers. Los despliegues PHP-FPM llaman a registerShutdownFlush() una vez en el arranque para que el resto se vacíe al final de la petición. Los workers de larga duración (Octane, worker de Symfony, worker de cola) deben vaciar mediante un temporizador periódico en su lugar; de lo contrario, las entradas se acumulan hasta que el proceso worker sale.
  • $bufferSize por debajo de 1. Viola el contrato documentado positive-int; el resultado observable es un vaciado en cada llamada a record().
  • Metadatos sensibles. $metadata es de formato libre y puede llevar contexto de operación sensible. El almacenamiento, la retención y el control de acceso son responsabilidad del operador del backend.
  • Fallo de entrega de Pushgateway. Una respuesta distinta de 2xx lanza PrometheusPushgatewayException que lleva el estado HTTP y el cuerpo de la respuesta; un fallo de transporte PSR-18 se envuelve en el mismo tipo de excepción. El bucle de reintento y aislamiento del reportador absorbe ambos.
  • Sonda de salud. PrometheusMeteringBackend::isHealthy() emite un GET contra <pushgatewayUrl>/-/healthy y devuelve true solo con HTTP 200. Cualquier error de transporte devuelve false; la sonda nunca lanza.
  • Valores de etiqueta hostiles. Los caracteres de barra invertida, comilla doble y salto de línea en los valores de operación o tenant se escapan en la emisión, de modo que un valor de etiqueta no puede inyectar líneas de exposición adicionales ni corromper el bloque de etiquetas.
  • Modo FIPS. El colector y el reportador no realizan operaciones criptográficas y no tienen comportamiento específico de FIPS. Un backend que firma o cifra en tránsito hereda la postura FIPS del proveedor de cifrado de su host.

Ningún estándar externo rige el contrato del colector, el reportador ni el backend en proceso; no hay una especificación normativa que citar, por lo que esta página no lleva ninguna cita RAG por diseño. El backend de Prometheus emite el formato de exposición de texto de Prometheus y envía con Content-Type text/plain; version=0.0.4; ese formato es una convención del ecosistema en lugar de un estándar ISO o IETF, y la afirmación se fundamenta en la fuente del producto. NextPDF no formula ninguna declaración de conformidad ni de certificación para esta superficie.

  • Todas las clases declaran strict_types=1 y son final; MeterEntry es final readonly con propiedades públicas promovidas. Los tipos de argumento no coincidentes lanzan un TypeError de PHP en quien invoca.
  • Las clases del módulo llevan una anotación de paquete @since de 2.1.0; PrometheusPushgatewayException lleva @since 3.2.0.
  • El logger del reportador tiene por defecto un NullLogger de PSR-3. Inyecte un logger real en producción, o los lotes descartados no dejarán rastro.
  • Pruebas unitarias: implemente un MeteringBackendInterface falso y construya valores MeterEntry directamente. El backend de Prometheus toma abstracciones PSR-18/PSR-17, por lo que un cliente HTTP simulado ejercita la ruta completa de push sin conexión.
  • Pruebas de límite recomendadas: búfer exactamente en $bufferSize, vaciado reentrante, vaciado con búfer vacío, un backend que falla mientras un segundo tiene éxito, y registro de agotamiento de reintentos.
  • Quienes implementen backends lanzan RuntimeException (o una subclase) ante un fallo de entrega; el reportador la absorbe. Respete el requisito de idempotencia antes de añadir más reintentos aguas arriba.

Esta página documenta únicamente el comportamiento observable externamente y la superficie de la API pública soportada. Las rutas de espacios de nombres internos, las clases auxiliares, las tablas de mecanismos, los nombres de archivo de runbooks y los prefijos de tickets están fuera de alcance.