Enterprise edition
Metering
At a glance
Section titled “At a glance”NextPDF Enterprise collects usage metering — operations, pages processed, durations — at the PHP orchestration layer for billing and audit. Entries are buffered in memory, flushed to one or more backends in batches, and a backend failure never blocks processing. This page describes the observable metering behavior and the public contract.
Availability & licensing
Section titled “Availability & licensing”This capability ships in NextPDF Enterprise (nextpdf/enterprise) and activates with an Enterprise-tier license envelope. A deployment without that entitlement does not load the capability’s classes. Metering is a base Enterprise capability with no separate per-feature flag. Compare editions and get a license.
Conceptual overview
Section titled “Conceptual overview”The metering collector records one immutable entry per operation: an operation type, a unit count, a timestamp, the tenant and license identifiers, pages processed, the operation duration, and free-form metadata. Entries accumulate in an in-memory buffer. When the buffer reaches its configured size it auto-flushes; you can also flush explicitly, and a shutdown handler can be registered so a PHP-FPM worker flushes any remainder at request end. A long-running worker (for example an Octane or Symfony worker) should flush on a periodic timer instead.
The reporter fans a batch out to one or more backends. Backends are isolated: a failure in one backend does not stop the others from receiving the batch. Each backend delivery is retried up to a configured attempt count; if all attempts fail the batch for that backend is logged and dropped — metering is best-effort and non-fatal by design, so a metering outage never degrades document processing. A backend is any implementation of the metering backend interface — a Prometheus push target, a billing API, a database, or a queue — and implementations are required to be idempotent so a duplicated batch is handled gracefully.
This orchestration-level metering is for billing and audit visibility. It is intentionally not the authoritative source for quota enforcement; quota decisions are made elsewhere in the deployment from an authoritative usage figure.
Why it works this way
Section titled “Why it works this way”Metering sits on the billing-and-audit path, not the document-processing path, and that separation is deliberate. Each record call appends one immutable MeterEntry to an in-memory buffer, so capturing usage stays an O(1) operation. Flushing happens in batches, fanned out to isolated backends behind the MeteringBackendInterface contract. A slow or dead billing endpoint then degrades gracefully, and an exhausted batch is logged and dropped rather than thrown. So a metering outage never stalls high-volume work or competes with document throughput. The trade-off is that orchestration metering is best-effort and non-authoritative — so quota enforcement is decided elsewhere from an authoritative figure.
Design background: High-volume document generation.
Public API surface
Section titled “Public API surface”composer require nextpdf/enterprise:^3The supported integration points are the meter collector (record, flush, bufferCount, registerShutdownFlush), the metering reporter (report), the metering backend interface (report, isHealthy, backendName), and the immutable meter entry value object. A no-retry-safe, idempotent backend implementation is your responsibility to provide for production durability.
Code sample — quick start
Section titled “Code sample — quick start”use NextPDF\Enterprise\Metering\MeterCollector;use NextPDF\Enterprise\Metering\MeteringReporter;
$collector = new MeterCollector(new MeteringReporter([$backend]), bufferSize: 100);$collector->registerShutdownFlush(); // PHP-FPM: flush remainder at request end
$collector->record( operation: 'parse', count: 1, tenantId: $tenantId, licenseId: $licenseId, pagesProcessed: 12, durationMs: 84.0,);Code sample — production
Section titled “Code sample — production”use NextPDF\Enterprise\Metering\MeteringReporter;
// Multi-backend fan-out with retry and failure isolation.$reporter = new MeteringReporter( backends: [$prometheusBackend, $billingApiBackend], maxRetries: 3, logger: $logger,);
// A failing billing API does not stop Prometheus from receiving the batch;// exhausted retries are logged and the batch is dropped — never thrown.$collector = new MeterCollector($reporter, bufferSize: 500);Edge cases & gotchas
Section titled “Edge cases & gotchas”- Flush is idempotent. Calling
flushon an empty buffer is a no-op; double-flush is safe. - Backend failure is non-fatal. Exhausted retries log an error and drop that backend’s batch; the call still returns normally. Do not rely on metering for hard quota enforcement.
- At least one backend is required. Constructing a reporter with an empty backend list is rejected.
- Idempotency is the backend’s job. The interface contract requires backends to dedupe (by timestamp, operation, and tenant) — a retried or duplicated batch must not double-count.
- Worker model matters. Use the shutdown handler for PHP-FPM; use a periodic timer flush for long-running workers, or entries buffer until the worker exits.
Performance
Section titled “Performance”record is an O(1) buffer append. Flush cost is proportional to the batch size and the number of backends; it is moved off the request path by buffering and by the shutdown handler. Retries apply per backend, bounded by the configured attempt count.
Security notes
Section titled “Security notes”Metering entries carry tenant and license identifiers and operation metadata. Treat metadata as potentially sensitive and scope your backend storage and retention to your compliance requirements. The tenant and license identifiers must originate from authenticated context.
Conformance
Section titled “Conformance”Metering defines no wire format of its own at the public boundary — the backend interface delegates serialization to each backend implementation (for example, a Prometheus push target follows the Prometheus exposition conventions). No external standard is asserted at this surface; there is no RAG citation for this page because no normative specification governs the in-process collector contract.
Behavior contract
Section titled “Behavior contract”- The collector records one immutable entry per operation and accumulates entries in an in-memory buffer that auto-flushes at its configured size; explicit flush and a shutdown-flush handler are also available.
- Flush is idempotent: flushing an empty buffer is a no-op and double-flush is safe.
- The reporter fans a batch out to one or more backends with per-backend isolation; one backend’s failure does not stop the others.
- Each backend delivery is retried up to the configured attempt count; exhausted retries are logged and dropped — metering is best-effort and never throws into the processing path.
- Constructing a reporter with an empty backend list is rejected; backends are required to be idempotent so a duplicated batch does not double-count.
recordis an O(1) buffer append; flush cost is proportional to batch size and backend count and is kept off the request path.
Publication boundary
Section titled “Publication boundary”This page documents externally observable behavior and the supported public API surface only. Internal namespace paths, helper classes, mechanism tables, runbook filenames, and ticket prefixes are out of scope.
Core fallback
Section titled “Core fallback”NextPDF Core (Apache-2.0) has no metering collector, reporter, or backend surface — none; this capability has no Core-tier equivalent. Core processing is not metered by NextPDF.
Pro fallback
Section titled “Pro fallback”NextPDF Pro has no metering surface — none; this capability has no Pro-tier equivalent. The meter collector, reporter, and backend interface ship in the nextpdf/enterprise package only.
Enterprise boundary note
Section titled “Enterprise boundary note”The buffer lifecycle, fan-out, retry, and isolation are described at the behavior level. The backend interface delegates serialization to each backend implementation; internal buffering internals and any internal fan-out detail are out of scope for the public surface.
Deployment boundary
Section titled “Deployment boundary”The operator owns the backend implementations, their durability and idempotency, the retention and storage scope of metering metadata, and the worker-model flush strategy (shutdown handler for PHP-FPM, periodic timer for long-running workers). A metering backend outage never degrades document processing. Tenant and license identifiers must originate from an authenticated context the operator configures.
Legal-compliance boundary
Section titled “Legal-compliance boundary”No export-control restriction applies to the metering surface. Metering metadata may be sensitive; retention and storage scope are the operator’s compliance responsibility. This documentation is not a legal opinion; consult your own compliance and legal advisers.