Enterprise edizione
Metering — Riferimento approfondito
In sintesi
Sezione intitolata “In sintesi”Il namespace NextPDF\Enterprise\Metering fornisce un metering dell’utilizzo a livello di orchestrazione per la visibilità di fatturazione e l’audit. La superficie pubblica è composta da sei simboli: MeterCollector, MeterEntry, MeteringReporter, MeteringBackendInterface, PrometheusMeteringBackend e PrometheusPushgatewayException. Il collector mette in buffer in memoria voci immutabili e le sottopone a flush in batch. Il reporter distribuisce (fan-out) ciascun batch verso uno o più backend con retry per backend e isolamento dei guasti. Il metering è best-effort e non fatale: un’interruzione di un backend di metering degrada l’osservabilità, mai l’elaborazione dei documenti. Questo stream non è la sorgente autorevole per l’applicazione delle quote. Per la guida a livello di workflow, vedere Metering.
Disponibilità e licenza
Sezione intitolata “Disponibilità e licenza”Questa capability è inclusa in NextPDF Enterprise (nextpdf/enterprise) e si attiva con un envelope di licenza di tier Enterprise. Una distribuzione priva di tale entitlement non carica le classi della capability. Confronta le edizioni e ottieni una licenza.
Il metering è una capability di base di Enterprise, disponibile una volta installato il pacchetto Enterprise; non esiste alcun flag separato per funzionalità. NextPDF Core (Apache-2.0) e NextPDF Pro non dispongono di alcuna superficie di collector, reporter o backend; il contratto è incluso esclusivamente in nextpdf/enterprise.
Superficie dell’API pubblica
Sezione intitolata “Superficie dell’API pubblica”| Simbolo | Parametri | Comportamento predefinito | Restituisce | Solleva o fallisce con | Note |
|---|---|---|---|---|---|
MeterCollector::__construct | MeteringReporter $reporter, int $bufferSize = 100 | Crea un collector con un buffer in memoria vuoto | Nuovo MeterCollector | Non solleva eccezioni | $bufferSize è documentato come positive-int |
MeterCollector::record | string $operation, int $count, string $tenantId, string $licenseId, int $pagesProcessed = 0, float $durationMs = 0.0, array $metadata = [] | Aggiunge una MeterEntry immutabile marcata con l’ora corrente; esegue un flush automatico quando il buffer raggiunge $bufferSize | void | Non solleva eccezioni; un flush automatico delega al reporter, che non solleva mai eccezioni | Il timestamp viene rilevato al momento della registrazione |
MeterCollector::flush | — | Consegna al reporter tutte le voci in buffer; un buffer vuoto è un no-op | void | Non solleva eccezioni; i guasti dei backend vengono assorbiti dal reporter | Il buffer viene scambiato (swap out) prima della consegna; sicuro in caso di rientranza |
MeterCollector::bufferCount | — | Restituisce il numero di voci in buffer | int<0, max> | Non solleva eccezioni | Diagnostica e decisioni di back-pressure |
MeterCollector::registerShutdownFlush | — | Registra flush() tramite register_shutdown_function | void | Non solleva eccezioni | Da chiamare una sola volta al bootstrap nelle distribuzioni PHP-FPM |
MeterEntry::__construct | string $operation, int $count, DateTimeImmutable $timestamp, string $tenantId, string $licenseId, int $pagesProcessed = 0, float $durationMs = 0.0, array $metadata = [] | Memorizza i valori forniti così come sono | Nuovo MeterEntry | Nessun @throws dichiarato; PHP solleva TypeError in caso di tipi di argomento non corrispondenti sotto strict_types | final readonly; tutte e otto le proprietà promosse sono pubbliche |
MeteringReporter::__construct | list<MeteringBackendInterface> $backends, int $maxRetries = 2, LoggerInterface $logger = new NullLogger() | Valida e memorizza l’elenco dei backend | Nuovo MeteringReporter | InvalidArgumentException quando $backends è vuoto | $maxRetries conta il totale dei tentativi di consegna per backend |
MeteringReporter::report | list<MeterEntry> $entries | Consegna il batch a ogni backend in modo indipendente, con retry per backend | void | Non solleva eccezioni; i tentativi esauriti vengono registrati a livello error e il batch di quel backend viene scartato | Un elenco vuoto è un no-op |
MeteringBackendInterface::report | list<MeterEntry> $entries | Consegna un batch al backend | void | RuntimeException quando il backend è irraggiungibile | Le implementazioni DEVONO essere idempotenti (deduplicazione per timestamp + operation + tenantId) |
MeteringBackendInterface::isHealthy | — | Sonda di raggiungibilità | bool | Nessun @throws dichiarato | Solo per diagnostica; il reporter non vi applica alcun gate |
MeteringBackendInterface::backendName | — | Nome del backend per la diagnostica | non-empty-string | Nessun @throws dichiarato | Per esempio "prometheus", "billing-api", "null" |
PrometheusMeteringBackend::__construct | ClientInterface $httpClient, RequestFactoryInterface $requestFactory, StreamFactoryInterface $streamFactory, string $pushgatewayUrl, string $jobName = 'nextpdf_metering' | Configura un target push Pushgateway | Nuovo PrometheusMeteringBackend | Non solleva eccezioni | Il client PSR-18 e le factory PSR-17 vengono iniettati |
PrometheusMeteringBackend::report | list<MeterEntry> $entries | Aggrega il batch per serie operazione-e-tenant ed esegue un POST del testo di esposizione verso <pushgatewayUrl>/metrics/job/<jobName> | void | PrometheusPushgatewayException in caso di status non-2xx o di guasto di trasporto PSR-18 | Un elenco vuoto è un no-op |
PrometheusMeteringBackend::isHealthy | — | Sonda l’endpoint di health del Pushgateway; true solo con HTTP 200 | bool | Non solleva eccezioni; qualsiasi guasto restituisce false | Sonda GET in sola lettura |
PrometheusMeteringBackend::backendName | — | Restituisce "prometheus" | non-empty-string | Non solleva eccezioni | Costante |
PrometheusPushgatewayException | — | Segnala una consegna Pushgateway fallita | — | È il throwable | final; estende 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(): voidpublic 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): voidpublic 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 {}Proprietà pubbliche readonly di MeterEntry
| Proprietà | Tipo | Significato |
|---|---|---|
$operation | non-empty-string | Tipo di operazione, per esempio "parse", "compress", "embed", "rag_query" |
$count | positive-int | Numero di unità consumate |
$timestamp | DateTimeImmutable | Quando è avvenuta l’operazione; il collector la marca al momento della registrazione |
$tenantId | non-empty-string | Identificatore del tenant |
$licenseId | non-empty-string | Identificatore della licenza |
$pagesProcessed | int<0, max> | Pagine PDF elaborate; 0 per operazioni non-PDF |
$durationMs | float | Durata dell’operazione in millisecondi |
$metadata | array<string, mixed> | Metadati specifici dell’operazione in formato libero |
Contratto di comportamento
Sezione intitolata “Contratto di comportamento”MeterCollector::record()costruisce unaMeterEntryimmutabile, la marca con l’ora corrente e la aggiunge al buffer in memoria. Quando il buffer raggiunge$bufferSizevoci, il collector esegue un flush automatico.flush()è idempotente e sicuro in caso di rientranza. Un buffer vuoto è un no-op. Il buffer viene scambiato (swap out) prima che il batch sia consegnato al reporter, così che un flush rientrante non possa causare un doppio invio.MeteringReporterrifiuta la costruzione con un elenco di backend vuoto. QuellaInvalidArgumentExceptionè l’unica eccezione sul percorso collector/reporter.MeteringReporter::report()consegna ciascun batch a ogni backend in modo indipendente. Un backend in errore non impedisce mai a un altro backend di ricevere lo stesso batch.$maxRetriesconta il totale dei tentativi di consegna per backend; il valore predefinito2significa un tentativo iniziale più un retry. Ogni tentativo fallito registra un warning con il nome del backend, il numero del tentativo e il conteggio delle voci.- Quando l’ultimo tentativo per un backend fallisce, il reporter registra inoltre a livello error con il conteggio delle voci scartate, poi prosegue. Non solleva mai eccezioni da
report(), quindi i chiamanti non devono dedurre la consegna da un ritorno normale. - I backend DEVONO essere idempotenti. Il contratto dell’interfaccia richiede una deduplicazione basata su timestamp, operazione e identificatore del tenant. Il reporter stesso non deduplica.
PrometheusMeteringBackend::report()aggrega il batch in serie per operazione e per tenant ed esegue un POST dell’esposizione testuale Prometheus verso<pushgatewayUrl>/metrics/job/<jobName>con Content-Typetext/plain; version=0.0.4. Il nome del job predefinito ènextpdf_metering.- Il payload inviato trasporta tre counter —
nextpdf_operations_total,nextpdf_pages_processed_totalenextpdf_operation_duration_ms_total— ciascuno etichettato per operazione e tenant. - Questo stream di metering non è autorevole. L’applicazione delle quote e il metering autorevole del compute consumano la cifra di utilizzo autorevole separata della distribuzione, mai questo buffer. Una lacuna nel metering di orchestrazione è una lacuna di osservabilità, non una lacuna di correttezza della fatturazione.
Casi limite e modalità di guasto
Sezione intitolata “Casi limite e modalità di guasto”- Batch duplicato o riprodotto (replayed). Assorbito dall’idempotenza del backend; il reporter non deduplica. Non fare affidamento su una consegna exactly-once.
- Retry esauriti. Il batch di quel backend viene scartato e registrato a livello error. Un ritorno normale da
report()oflush()non implica mai la consegna. - Uscita del processo prima del flush. Il buffer è solo in memoria. Un crash, o un’uscita senza uno shutdown handler registrato, perde le voci in buffer.
- Disallineamento del modello di worker. Le distribuzioni PHP-FPM chiamano
registerShutdownFlush()una sola volta al bootstrap, così che il resto venga sottoposto a flush alla fine della richiesta. I worker a lunga esecuzione (Octane, worker Symfony, queue worker) devono invece eseguire il flush su un timer periodico; altrimenti le voci si accumulano finché il processo worker non termina. $bufferSizeinferiore a1. Viola il contratto documentatopositive-int; il risultato osservabile è un flush a ogni chiamatarecord().- Metadati sensibili.
$metadataè in formato libero e può trasportare contesto operativo sensibile. Storage, conservazione e controllo degli accessi sono responsabilità dell’operatore del backend. - Guasto di consegna Pushgateway. Una risposta non-2xx solleva
PrometheusPushgatewayExceptionche trasporta lo status HTTP e il corpo della risposta; un guasto di trasporto PSR-18 viene incapsulato nello stesso tipo di eccezione. Il ciclo di retry e isolamento del reporter assorbe entrambi. - Sonda di health.
PrometheusMeteringBackend::isHealthy()esegue una GET verso<pushgatewayUrl>/-/healthye restituiscetruesolo con HTTP 200. Qualsiasi errore di trasporto restituiscefalse; la sonda non solleva mai eccezioni. - Valori di label ostili. I caratteri backslash, doppio apice e line-feed nei valori di operazione o tenant vengono sottoposti a escape al momento dell’emissione, così che un valore di label non possa iniettare righe di esposizione aggiuntive né corrompere il blocco delle label.
- Modalità FIPS. Il collector e il reporter non eseguono alcuna operazione crittografica e non hanno alcun comportamento specifico per FIPS. Un backend che firma o cifra in transito eredita la postura FIPS del provider crittografico del proprio host.
Conformità
Sezione intitolata “Conformità”Nessuno standard esterno governa il contratto in-process del collector, del reporter o del backend; non esiste alcuna specifica normativa da citare, quindi questa pagina non riporta alcuna citazione RAG, per progettazione. Il backend Prometheus emette il formato di esposizione testuale Prometheus ed esegue il push con Content-Type text/plain; version=0.0.4; tale formato è una convenzione dell’ecosistema piuttosto che uno standard ISO o IETF, e l’affermazione è fondata sul codice sorgente del prodotto. NextPDF non avanza alcuna dichiarazione di conformità o certificazione per questa superficie.
Note di sviluppo
Sezione intitolata “Note di sviluppo”- Tutte le classi dichiarano
strict_types=1e sonofinal;MeterEntryèfinal readonlycon proprietà pubbliche promosse. Tipi di argomento non corrispondenti sollevano unTypeErrorPHP nel chiamante. - Le classi del modulo riportano un’annotazione di pacchetto
@sincepari a2.1.0;PrometheusPushgatewayExceptionriporta@since3.2.0. - Il logger del reporter è per impostazione predefinita un
NullLoggerPSR-3. Iniettare un logger reale in produzione, altrimenti i batch scartati non lasciano alcuna traccia. - Test unitari: implementare un fake di
MeteringBackendInterfacee costruire direttamente i valoriMeterEntry. Il backend Prometheus accetta astrazioni PSR-18/PSR-17, quindi un client HTTP mock esercita l’intero percorso di push offline. - Test di confine consigliati: buffer esattamente a
$bufferSize, flush rientrante, flush con buffer vuoto, un backend che fallisce mentre un secondo ha successo, e logging di esaurimento dei retry. - Chi implementa un backend solleva
RuntimeException(o una sottoclasse) in caso di guasto di consegna; il reporter la assorbe. Rispettare il requisito di idempotenza prima di aggiungere ulteriori retry a monte.
Confine di pubblicazione
Sezione intitolata “Confine di pubblicazione”Questa pagina documenta esclusivamente il comportamento osservabile dall’esterno e la superficie dell’API pubblica supportata. I percorsi di namespace interni, le classi helper, le tabelle dei meccanismi, i nomi di file dei runbook e i prefissi dei ticket sono fuori ambito.
Vedere anche
Sezione intitolata “Vedere anche”- Metering — NextPDF Enterprise — la pagina della capability: workflow, configurazione ed esempi di distribuzione svolti.
- Billing — Riferimento approfondito — i tier dei piani, la semantica degli overage e la scala degli alert.
- SaaS — Riferimento approfondito — la superficie di orchestrazione multi-tenant.
- Licensing — Riferimento approfondito — l’envelope di licenza che attiva le capability Enterprise.