Enterprise Edition
Verbrauchsmessung — Ausführliche Referenz
Auf einen Blick
Abschnitt betitelt „Auf einen Blick“Der Namespace NextPDF\Enterprise\Metering liefert Verbrauchsmessung auf Orchestrierungsebene für Abrechnungssichtbarkeit und Audit. Die öffentliche Oberfläche umfasst sechs Symbole: MeterCollector, MeterEntry, MeteringReporter, MeteringBackendInterface, PrometheusMeteringBackend und PrometheusPushgatewayException. Der Collector puffert unveränderliche Einträge im Arbeitsspeicher und flusht sie in Batches. Der Reporter verteilt jeden Batch per Fan-out an ein oder mehrere Backends mit Retry pro Backend und Fehlerisolation. Metering ist Best-Effort und nicht-fatal: Ein Ausfall eines Metering-Backends degradiert die Beobachtbarkeit, niemals die Dokumentverarbeitung. Dieser Stream ist nicht die maßgebliche Quelle für die Quota-Durchsetzung. Den Leitfaden auf Workflow-Ebene finden Sie unter Metering.
Verfügbarkeit & Lizenzierung
Abschnitt betitelt „Verfügbarkeit & Lizenzierung“Diese Fähigkeit wird in NextPDF Enterprise (nextpdf/enterprise) ausgeliefert und aktiviert sich mit einem Lizenz-Envelope der Enterprise-Stufe. Ein Deployment ohne diese Berechtigung lädt die Klassen der Fähigkeit nicht. Editionen vergleichen und Lizenz erwerben.
Metering ist eine Basis-Enterprise-Fähigkeit, die verfügbar ist, sobald das Enterprise-Paket installiert ist; es gibt kein separates funktionsbezogenes Flag. NextPDF Core (Apache-2.0) und NextPDF Pro besitzen keine Collector-, Reporter- oder Backend-Oberfläche; der Vertrag wird ausschließlich in nextpdf/enterprise ausgeliefert.
Öffentliche API-Oberfläche
Abschnitt betitelt „Öffentliche API-Oberfläche“| Symbol | Parameter | Standardverhalten | Rückgabe | Wirft oder scheitert mit | Hinweise |
|---|---|---|---|---|---|
MeterCollector::__construct | MeteringReporter $reporter, int $bufferSize = 100 | Erzeugt einen Collector mit leerem In-Memory-Puffer | Neuer MeterCollector | Wirft nicht | $bufferSize ist als positive-int dokumentiert |
MeterCollector::record | string $operation, int $count, string $tenantId, string $licenseId, int $pagesProcessed = 0, float $durationMs = 0.0, array $metadata = [] | Hängt einen unveränderlichen MeterEntry an, gestempelt mit der aktuellen Zeit; flusht automatisch, wenn der Puffer $bufferSize erreicht | void | Wirft nicht; ein Auto-Flush delegiert an den Reporter, der niemals wirft | Der Zeitstempel wird zum Zeitpunkt der Erfassung genommen |
MeterCollector::flush | — | Übergibt alle gepufferten Einträge an den Reporter; leerer Puffer ist eine No-op | void | Wirft nicht; Backend-Fehler werden vom Reporter absorbiert | Der Puffer wird vor der Übergabe ausgetauscht; wiedereintrittssicher |
MeterCollector::bufferCount | — | Gibt die Anzahl der gepufferten Einträge zurück | int<0, max> | Wirft nicht | Diagnose- und Back-Pressure-Entscheidungen |
MeterCollector::registerShutdownFlush | — | Registriert flush() über register_shutdown_function | void | Wirft nicht | Einmal beim Bootstrap in PHP-FPM-Deployments aufrufen |
MeterEntry::__construct | string $operation, int $count, DateTimeImmutable $timestamp, string $tenantId, string $licenseId, int $pagesProcessed = 0, float $durationMs = 0.0, array $metadata = [] | Speichert die übergebenen Werte unverändert | Neuer MeterEntry | Kein deklariertes @throws; PHP löst unter strict_types bei nicht passenden Argumenttypen einen TypeError aus | final readonly; alle acht promoteten Eigenschaften sind public |
MeteringReporter::__construct | list<MeteringBackendInterface> $backends, int $maxRetries = 2, LoggerInterface $logger = new NullLogger() | Validiert und speichert die Backend-Liste | Neuer MeteringReporter | InvalidArgumentException, wenn $backends leer ist | $maxRetries zählt die Gesamtzahl der Zustellversuche pro Backend |
MeteringReporter::report | list<MeterEntry> $entries | Liefert den Batch unabhängig an jedes Backend aus, mit Retry pro Backend | void | Wirft nicht; erschöpfte Versuche protokollieren auf Error-Level und verwerfen den Batch dieses Backends | Leere Liste ist eine No-op |
MeteringBackendInterface::report | list<MeterEntry> $entries | Liefert einen Batch an das Backend | void | RuntimeException, wenn das Backend nicht erreichbar ist | Implementierungen MÜSSEN idempotent sein (Deduplizierung nach timestamp + operation + tenantId) |
MeteringBackendInterface::isHealthy | — | Erreichbarkeits-Probe | bool | Kein deklariertes @throws | Nur Diagnose; der Reporter macht sie nicht zur Bedingung |
MeteringBackendInterface::backendName | — | Diagnostischer Backend-Name | non-empty-string | Kein deklariertes @throws | Zum Beispiel "prometheus", "billing-api", "null" |
PrometheusMeteringBackend::__construct | ClientInterface $httpClient, RequestFactoryInterface $requestFactory, StreamFactoryInterface $streamFactory, string $pushgatewayUrl, string $jobName = 'nextpdf_metering' | Konfiguriert ein Pushgateway-Push-Ziel | Neuer PrometheusMeteringBackend | Wirft nicht | PSR-18-Client und PSR-17-Factories werden injiziert |
PrometheusMeteringBackend::report | list<MeterEntry> $entries | Aggregiert den Batch nach Serien aus Operation und Mandant und POSTet Expositionstext an <pushgatewayUrl>/metrics/job/<jobName> | void | PrometheusPushgatewayException bei einem Nicht-2xx-Status oder einem PSR-18-Transportfehler | Leere Liste ist eine No-op |
PrometheusMeteringBackend::isHealthy | — | Prüft den Health-Endpunkt des Pushgateway; true nur bei HTTP 200 | bool | Wirft nicht; jeder Fehler gibt false zurück | Read-only-GET-Probe |
PrometheusMeteringBackend::backendName | — | Gibt "prometheus" zurück | non-empty-string | Wirft nicht | Konstante |
PrometheusPushgatewayException | — | Signalisiert eine fehlgeschlagene Pushgateway-Zustellung | — | Ist das Throwable | final; erweitert 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 {}Öffentliche Readonly-Eigenschaften von MeterEntry
| Eigenschaft | Typ | Bedeutung |
|---|---|---|
$operation | non-empty-string | Operationstyp, zum Beispiel "parse", "compress", "embed", "rag_query" |
$count | positive-int | Anzahl der verbrauchten Einheiten |
$timestamp | DateTimeImmutable | Wann die Operation stattfand; der Collector stempelt ihn zum Zeitpunkt der Erfassung |
$tenantId | non-empty-string | Mandantenkennung |
$licenseId | non-empty-string | Lizenzkennung |
$pagesProcessed | int<0, max> | Verarbeitete PDF-Seiten; 0 für Nicht-PDF-Operationen |
$durationMs | float | Operationsdauer in Millisekunden |
$metadata | array<string, mixed> | Frei formulierte operationsspezifische Metadaten |
Verhaltensvertrag
Abschnitt betitelt „Verhaltensvertrag“MeterCollector::record()konstruiert einen unveränderlichenMeterEntry, stempelt ihn mit der aktuellen Zeit und hängt ihn an den In-Memory-Puffer an. Wenn der Puffer$bufferSizeEinträge erreicht, flusht der Collector automatisch.flush()ist idempotent und wiedereintrittssicher. Ein leerer Puffer ist eine No-op. Der Puffer wird ausgetauscht, bevor der Batch an den Reporter übergeben wird, sodass ein wiedereintretender Flush nicht doppelt senden kann.MeteringReporterlehnt die Konstruktion mit einer leeren Backend-Liste ab. DieseInvalidArgumentExceptionist die einzige Exception auf dem Collector-/Reporter-Pfad.MeteringReporter::report()liefert jeden Batch unabhängig an jedes Backend aus. Ein scheiterndes Backend hindert niemals ein anderes Backend daran, denselben Batch zu erhalten.$maxRetrieszählt die Gesamtzahl der Zustellversuche pro Backend; der Standardwert2bedeutet einen ersten Versuch plus einen Retry. Jeder fehlgeschlagene Versuch protokolliert eine Warnung mit Backend-Name, Versuchsnummer und Eintragsanzahl.- Wenn der letzte Versuch für ein Backend scheitert, protokolliert der Reporter zusätzlich auf Error-Level mit der Anzahl verworfener Einträge und fährt dann fort. Er wirft niemals aus
report(), daher dürfen Aufrufer aus einer normalen Rückkehr keine Zustellung ableiten. - Backends MÜSSEN idempotent sein. Der Interface-Vertrag erfordert eine Deduplizierung mit Schlüssel aus Zeitstempel, Operation und Mandantenkennung. Der Reporter selbst dedupliziert nicht.
PrometheusMeteringBackend::report()aggregiert den Batch in Serien pro Operation und pro Mandant und POSTet Prometheus-Textexposition an<pushgatewayUrl>/metrics/job/<jobName>mit Content-Typetext/plain; version=0.0.4. Der Standard-Job-Name istnextpdf_metering.- Die gepushte Payload trägt drei Counter —
nextpdf_operations_total,nextpdf_pages_processed_totalundnextpdf_operation_duration_ms_total— jeweils beschriftet nach Operation und Mandant. - Dieser Metering-Stream ist nicht maßgeblich. Die Quota-Durchsetzung und das maßgebliche Compute-Metering verbrauchen die separate maßgebliche Nutzungskennzahl des Deployments, niemals diesen Puffer. Eine Lücke im Orchestrierungs-Metering ist eine Lücke in der Beobachtbarkeit, keine Lücke in der Abrechnungskorrektheit.
Grenzfälle & Fehlermodi
Abschnitt betitelt „Grenzfälle & Fehlermodi“- Duplizierter oder erneut abgespielter Batch. Wird durch die Backend-Idempotenz absorbiert; der Reporter dedupliziert nicht. Verlassen Sie sich nicht auf Exactly-once-Zustellung.
- Erschöpfte Retries. Der Batch für dieses Backend wird verworfen und auf Error-Level protokolliert. Eine normale Rückkehr aus
report()oderflush()impliziert niemals eine Zustellung. - Prozessende vor dem Flush. Der Puffer liegt ausschließlich im Arbeitsspeicher. Ein Absturz oder ein Beenden ohne registrierten Shutdown-Handler verliert die gepufferten Einträge.
- Nicht passendes Worker-Modell. PHP-FPM-Deployments rufen
registerShutdownFlush()einmal beim Bootstrap auf, sodass der Rest am Anfragenende geflusht wird. Langlaufende Worker (Octane, Symfony-Worker, Queue-Worker) müssen stattdessen auf einem periodischen Timer flushen; andernfalls sammeln sich Einträge an, bis der Worker-Prozess beendet wird. $bufferSizeunter1. Verletzt den dokumentiertenpositive-int-Vertrag; das beobachtbare Resultat ist ein Flush bei jedemrecord()-Aufruf.- Sensible Metadaten.
$metadataist frei formuliert und kann sensiblen Operationskontext tragen. Speicherung, Aufbewahrung und Zugriffskontrolle liegen in der Verantwortung des Backend-Betreibers. - Pushgateway-Zustellfehler. Eine Nicht-2xx-Antwort löst eine
PrometheusPushgatewayExceptionaus, die HTTP-Status und Antwort-Body trägt; ein PSR-18-Transportfehler wird in denselben Exception-Typ verpackt. Die Retry-und-Isolations-Schleife des Reporters absorbiert beide. - Health-Probe.
PrometheusMeteringBackend::isHealthy()sendet ein GET an<pushgatewayUrl>/-/healthyund gibttruenur bei HTTP 200 zurück. Jeder Transportfehler gibtfalsezurück; die Probe wirft niemals. - Feindselige Label-Werte. Backslash-, doppelte Anführungszeichen- und Zeilenvorschub-Zeichen in Operations- oder Mandantenwerten werden bei der Ausgabe escaped, sodass ein Label-Wert keine zusätzlichen Expositionszeilen einschleusen oder den Label-Block beschädigen kann.
- FIPS-Modus. Der Collector und der Reporter führen keine kryptografischen Operationen durch und haben kein FIPS-spezifisches Verhalten. Ein Backend, das im Transit signiert oder verschlüsselt, erbt die FIPS-Haltung seines Host-Krypto-Providers.
Konformität
Abschnitt betitelt „Konformität“Kein externer Standard regelt den In-process-Vertrag von Collector, Reporter oder Backend; es gibt keine normative Spezifikation zum Zitieren, daher trägt diese Seite konstruktionsbedingt keine RAG-Zitation. Das Prometheus-Backend gibt das Prometheus-Textexpositionsformat aus und pusht mit Content-Type text/plain; version=0.0.4; dieses Format ist eine Ökosystem-Konvention und kein ISO- oder IETF-Standard, und die Aussage ist in der Produktquelle verankert. NextPDF erhebt für diese Oberfläche keinen Konformitäts- oder Zertifizierungsanspruch.
Entwicklungshinweise
Abschnitt betitelt „Entwicklungshinweise“- Alle Klassen deklarieren
strict_types=1und sindfinal;MeterEntryistfinal readonlymit promoteten Public-Eigenschaften. Nicht passende Argumenttypen lösen im Aufrufer einen PHP-TypeErroraus. - Die Modulklassen tragen eine Paket-
@since-Annotation von2.1.0;PrometheusPushgatewayExceptionträgt@since3.2.0. - Der Logger des Reporters ist standardmäßig ein PSR-3-
NullLogger. Injizieren Sie in der Produktion einen echten Logger, sonst hinterlassen verworfene Batches keine Spur. - Unit-Tests: Implementieren Sie ein Fake-
MeteringBackendInterfaceund konstruieren SieMeterEntry-Werte direkt. Das Prometheus-Backend nimmt PSR-18-/PSR-17-Abstraktionen, sodass ein Mock-HTTP-Client den vollständigen Push-Pfad offline durchläuft. - Empfohlene Grenzfalltests: Puffer exakt bei
$bufferSize, wiedereintretender Flush, Flush mit leerem Puffer, ein Backend scheitert, während ein zweites erfolgreich ist, und Protokollierung der Retry-Erschöpfung. - Backend-Implementierer werfen bei Zustellfehlern
RuntimeException(oder eine Unterklasse); der Reporter absorbiert sie. Beachten Sie die Idempotenzanforderung, bevor Sie vorgelagert weitere Retries hinzufügen.
Veröffentlichungsgrenze
Abschnitt betitelt „Veröffentlichungsgrenze“Diese Seite dokumentiert ausschließlich extern beobachtbares Verhalten und die unterstützte öffentliche API-Oberfläche. Interne Namespace-Pfade, Hilfsklassen, Mechanismustabellen, Runbook-Dateinamen und Ticket-Präfixe liegen außerhalb des Umfangs.
Siehe auch
Abschnitt betitelt „Siehe auch“- Metering — NextPDF Enterprise — die Fähigkeitsseite: Workflow, Konfiguration und ausgearbeitete Deployment-Beispiele.
- Billing — Detailreferenz — Plan-Stufen, Overage-Semantik und die Alert-Leiter.
- SaaS — Ausführliche Referenz — die mandantenfähige Orchestrierungsoberfläche.
- Licensing — Detailreferenz — der Lizenz-Envelope, der Enterprise-Fähigkeiten aktiviert.