Zum Inhalt springen
getnextpdf.com

Enterprise Edition

Verbrauchsmessung — Ausführliche Referenz

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.

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.

SymbolParameterStandardverhaltenRückgabeWirft oder scheitert mitHinweise
MeterCollector::__constructMeteringReporter $reporter, int $bufferSize = 100Erzeugt einen Collector mit leerem In-Memory-PufferNeuer MeterCollectorWirft nicht$bufferSize ist als positive-int dokumentiert
MeterCollector::recordstring $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 erreichtvoidWirft nicht; ein Auto-Flush delegiert an den Reporter, der niemals wirftDer Zeitstempel wird zum Zeitpunkt der Erfassung genommen
MeterCollector::flushÜbergibt alle gepufferten Einträge an den Reporter; leerer Puffer ist eine No-opvoidWirft nicht; Backend-Fehler werden vom Reporter absorbiertDer Puffer wird vor der Übergabe ausgetauscht; wiedereintrittssicher
MeterCollector::bufferCountGibt die Anzahl der gepufferten Einträge zurückint<0, max>Wirft nichtDiagnose- und Back-Pressure-Entscheidungen
MeterCollector::registerShutdownFlushRegistriert flush() über register_shutdown_functionvoidWirft nichtEinmal beim Bootstrap in PHP-FPM-Deployments aufrufen
MeterEntry::__constructstring $operation, int $count, DateTimeImmutable $timestamp, string $tenantId, string $licenseId, int $pagesProcessed = 0, float $durationMs = 0.0, array $metadata = []Speichert die übergebenen Werte unverändertNeuer MeterEntryKein deklariertes @throws; PHP löst unter strict_types bei nicht passenden Argumenttypen einen TypeError ausfinal readonly; alle acht promoteten Eigenschaften sind public
MeteringReporter::__constructlist<MeteringBackendInterface> $backends, int $maxRetries = 2, LoggerInterface $logger = new NullLogger()Validiert und speichert die Backend-ListeNeuer MeteringReporterInvalidArgumentException, wenn $backends leer ist$maxRetries zählt die Gesamtzahl der Zustellversuche pro Backend
MeteringReporter::reportlist<MeterEntry> $entriesLiefert den Batch unabhängig an jedes Backend aus, mit Retry pro BackendvoidWirft nicht; erschöpfte Versuche protokollieren auf Error-Level und verwerfen den Batch dieses BackendsLeere Liste ist eine No-op
MeteringBackendInterface::reportlist<MeterEntry> $entriesLiefert einen Batch an das BackendvoidRuntimeException, wenn das Backend nicht erreichbar istImplementierungen MÜSSEN idempotent sein (Deduplizierung nach timestamp + operation + tenantId)
MeteringBackendInterface::isHealthyErreichbarkeits-ProbeboolKein deklariertes @throwsNur Diagnose; der Reporter macht sie nicht zur Bedingung
MeteringBackendInterface::backendNameDiagnostischer Backend-Namenon-empty-stringKein deklariertes @throwsZum Beispiel "prometheus", "billing-api", "null"
PrometheusMeteringBackend::__constructClientInterface $httpClient, RequestFactoryInterface $requestFactory, StreamFactoryInterface $streamFactory, string $pushgatewayUrl, string $jobName = 'nextpdf_metering'Konfiguriert ein Pushgateway-Push-ZielNeuer PrometheusMeteringBackendWirft nichtPSR-18-Client und PSR-17-Factories werden injiziert
PrometheusMeteringBackend::reportlist<MeterEntry> $entriesAggregiert den Batch nach Serien aus Operation und Mandant und POSTet Expositionstext an <pushgatewayUrl>/metrics/job/<jobName>voidPrometheusPushgatewayException bei einem Nicht-2xx-Status oder einem PSR-18-TransportfehlerLeere Liste ist eine No-op
PrometheusMeteringBackend::isHealthyPrüft den Health-Endpunkt des Pushgateway; true nur bei HTTP 200boolWirft nicht; jeder Fehler gibt false zurückRead-only-GET-Probe
PrometheusMeteringBackend::backendNameGibt "prometheus" zurücknon-empty-stringWirft nichtKonstante
PrometheusPushgatewayExceptionSignalisiert eine fehlgeschlagene Pushgateway-ZustellungIst das Throwablefinal; 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(): 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 {}

Öffentliche Readonly-Eigenschaften von MeterEntry

EigenschaftTypBedeutung
$operationnon-empty-stringOperationstyp, zum Beispiel "parse", "compress", "embed", "rag_query"
$countpositive-intAnzahl der verbrauchten Einheiten
$timestampDateTimeImmutableWann die Operation stattfand; der Collector stempelt ihn zum Zeitpunkt der Erfassung
$tenantIdnon-empty-stringMandantenkennung
$licenseIdnon-empty-stringLizenzkennung
$pagesProcessedint<0, max>Verarbeitete PDF-Seiten; 0 für Nicht-PDF-Operationen
$durationMsfloatOperationsdauer in Millisekunden
$metadataarray<string, mixed>Frei formulierte operationsspezifische Metadaten
  • MeterCollector::record() konstruiert einen unveränderlichen MeterEntry, stempelt ihn mit der aktuellen Zeit und hängt ihn an den In-Memory-Puffer an. Wenn der Puffer $bufferSize Einträ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.
  • MeteringReporter lehnt die Konstruktion mit einer leeren Backend-Liste ab. Diese InvalidArgumentException ist 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.
  • $maxRetries zählt die Gesamtzahl der Zustellversuche pro Backend; der Standardwert 2 bedeutet 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-Type text/plain; version=0.0.4. Der Standard-Job-Name ist nextpdf_metering.
  • Die gepushte Payload trägt drei Counter — nextpdf_operations_total, nextpdf_pages_processed_total und nextpdf_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.
  • 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() oder flush() 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.
  • $bufferSize unter 1. Verletzt den dokumentierten positive-int-Vertrag; das beobachtbare Resultat ist ein Flush bei jedem record()-Aufruf.
  • Sensible Metadaten. $metadata ist 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 PrometheusPushgatewayException aus, 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>/-/healthy und gibt true nur bei HTTP 200 zurück. Jeder Transportfehler gibt false zurü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.

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.

  • Alle Klassen deklarieren strict_types=1 und sind final; MeterEntry ist final readonly mit promoteten Public-Eigenschaften. Nicht passende Argumenttypen lösen im Aufrufer einen PHP-TypeError aus.
  • Die Modulklassen tragen eine Paket-@since-Annotation von 2.1.0; PrometheusPushgatewayException trägt @since 3.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-MeteringBackendInterface und konstruieren Sie MeterEntry-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.

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.