Pular para o conteúdo
getnextpdf.com

Enterprise edição

Metering — Referência Profunda

O namespace NextPDF\Enterprise\Metering distribui medição de uso no nível de orquestração para visibilidade de cobrança e auditoria. A superfície pública é de seis símbolos: MeterCollector, MeterEntry, MeteringReporter, MeteringBackendInterface, PrometheusMeteringBackend e PrometheusPushgatewayException. O coletor faz buffer de entradas imutáveis na memória e as descarrega em lotes. O reporter distribui cada lote para um ou mais backends com retentativa por backend e isolamento de falhas. A medição é de melhor esforço e não fatal: uma indisponibilidade de backend de medição degrada a observabilidade, nunca o processamento de documentos. Este fluxo não é a fonte autoritativa para a imposição de cota. Para o guia no nível de fluxo de trabalho, consulte Metering.

Este recurso é distribuído no NextPDF Enterprise (nextpdf/enterprise) e é ativado com um envelope de licença de nível Enterprise. Uma implantação sem essa habilitação não carrega as classes do recurso. Compare edições e obtenha uma licença.

A medição é um recurso base do Enterprise, disponível assim que o pacote Enterprise é instalado; não há um sinalizador separado por recurso. NextPDF Core (Apache-2.0) e NextPDF Pro não têm superfície de coletor, reporter ou backend; o contrato é distribuído apenas em nextpdf/enterprise.

SímboloParâmetrosComportamento padrãoRetornaLança ou falha comNotas
MeterCollector::__constructMeteringReporter $reporter, int $bufferSize = 100Cria um coletor com um buffer em memória vazioNovo MeterCollectorNão lança exceção$bufferSize é documentado como positive-int
MeterCollector::recordstring $operation, int $count, string $tenantId, string $licenseId, int $pagesProcessed = 0, float $durationMs = 0.0, array $metadata = []Anexa um MeterEntry imutável carimbado com a hora atual; faz flush automático quando o buffer atinge $bufferSizevoidNão lança exceção; um flush automático delega ao reporter, que nunca lança exceçãoO timestamp é obtido no momento do registro
MeterCollector::flushEntrega todas as entradas em buffer ao reporter; um buffer vazio é um no-opvoidNão lança exceção; falhas de backend são absorvidas pelo reporterO buffer é trocado antes da entrega; seguro para reentrância
MeterCollector::bufferCountRetorna o número de entradas em bufferint<0, max>Não lança exceçãoDiagnósticos e decisões de contrapressão (back-pressure)
MeterCollector::registerShutdownFlushRegistra flush() por meio de register_shutdown_functionvoidNão lança exceçãoChame uma vez no bootstrap em implantações PHP-FPM
MeterEntry::__constructstring $operation, int $count, DateTimeImmutable $timestamp, string $tenantId, string $licenseId, int $pagesProcessed = 0, float $durationMs = 0.0, array $metadata = []Armazena os valores fornecidos literalmenteNovo MeterEntrySem @throws declarado; o PHP levanta TypeError em tipos de argumento incompatíveis sob strict_typesfinal readonly; todas as oito propriedades promovidas são públicas
MeteringReporter::__constructlist<MeteringBackendInterface> $backends, int $maxRetries = 2, LoggerInterface $logger = new NullLogger()Valida e armazena a lista de backendsNovo MeteringReporterInvalidArgumentException quando $backends está vazio$maxRetries conta o total de tentativas de entrega por backend
MeteringReporter::reportlist<MeterEntry> $entriesEntrega o lote a cada backend de forma independente, com retentativa por backendvoidNão lança exceção; tentativas esgotadas são registradas em nível de erro e o lote daquele backend é descartadoUma lista vazia é um no-op
MeteringBackendInterface::reportlist<MeterEntry> $entriesEntrega um lote ao backendvoidRuntimeException quando o backend está inacessívelAs implementações DEVEM ser idempotentes (dedupe por timestamp + operation + tenantId)
MeteringBackendInterface::isHealthySonda de acessibilidadeboolSem @throws declaradoApenas diagnósticos; o reporter não depende dela
MeteringBackendInterface::backendNameNome de backend para diagnósticonon-empty-stringSem @throws declaradoPor exemplo "prometheus", "billing-api", "null"
PrometheusMeteringBackend::__constructClientInterface $httpClient, RequestFactoryInterface $requestFactory, StreamFactoryInterface $streamFactory, string $pushgatewayUrl, string $jobName = 'nextpdf_metering'Configura um alvo de push do PushgatewayNovo PrometheusMeteringBackendNão lança exceçãoO cliente PSR-18 e as factories PSR-17 são injetados
PrometheusMeteringBackend::reportlist<MeterEntry> $entriesAgrega o lote por série de operação-e-tenant e faz POST do texto de exposição para <pushgatewayUrl>/metrics/job/<jobName>voidPrometheusPushgatewayException em um status não-2xx ou uma falha de transporte PSR-18Uma lista vazia é um no-op
PrometheusMeteringBackend::isHealthySonda o endpoint de saúde do Pushgateway; true apenas em HTTP 200boolNão lança exceção; qualquer falha retorna falseSonda GET somente leitura
PrometheusMeteringBackend::backendNameRetorna "prometheus"non-empty-stringNão lança exceçãoConstante
PrometheusPushgatewayExceptionSinaliza uma entrega do Pushgateway com falhaÉ o throwablefinal; 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(): 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 {}

Propriedades públicas readonly de MeterEntry

PropriedadeTipoSignificado
$operationnon-empty-stringTipo de operação, por exemplo "parse", "compress", "embed", "rag_query"
$countpositive-intNúmero de unidades consumidas
$timestampDateTimeImmutableQuando a operação ocorreu; o coletor a carimba no momento do registro
$tenantIdnon-empty-stringIdentificador do tenant
$licenseIdnon-empty-stringIdentificador da licença
$pagesProcessedint<0, max>Páginas PDF processadas; 0 para operações não-PDF
$durationMsfloatDuração da operação em milissegundos
$metadataarray<string, mixed>Metadados específicos da operação, de formato livre
  • MeterCollector::record() constrói um MeterEntry imutável, carimba-o com a hora atual e o anexa ao buffer em memória. Quando o buffer atinge $bufferSize entradas, o coletor faz flush automático.
  • flush() é idempotente e seguro para reentrância. Um buffer vazio é um no-op. O buffer é trocado antes que o lote seja entregue ao reporter, de modo que um flush reentrante não possa enviar em duplicidade.
  • MeteringReporter rejeita a construção com uma lista de backends vazia. Essa InvalidArgumentException é a única exceção no caminho do coletor/reporter.
  • MeteringReporter::report() entrega cada lote a todos os backends de forma independente. Um backend com falha nunca impede que outro backend receba o mesmo lote.
  • $maxRetries conta o total de tentativas de entrega por backend; o padrão de 2 significa uma tentativa inicial mais uma retentativa. Cada tentativa com falha registra um aviso com o nome do backend, o número da tentativa e a contagem de entradas.
  • Quando a tentativa final de um backend falha, o reporter adicionalmente registra em nível de erro com a contagem de entradas descartadas e então segue adiante. Ele nunca lança exceção a partir de report(), então os chamadores não devem inferir a entrega a partir de um retorno normal.
  • Os backends DEVEM ser idempotentes. O contrato da interface exige deduplicação com chave em timestamp, operação e identificador do tenant. O próprio reporter não deduplica.
  • PrometheusMeteringBackend::report() agrega o lote em séries por operação e por tenant e faz POST da exposição de texto do Prometheus para <pushgatewayUrl>/metrics/job/<jobName> com Content-Type text/plain; version=0.0.4. O nome de job padrão é nextpdf_metering.
  • O payload enviado carrega três counters — nextpdf_operations_total, nextpdf_pages_processed_total e nextpdf_operation_duration_ms_total — cada um rotulado por operação e tenant.
  • Este fluxo de medição não é autoritativo. A imposição de cota e a medição autoritativa de computação consomem o número de uso autoritativo separado da implantação, nunca este buffer. Uma lacuna na medição de orquestração é uma lacuna de observabilidade, não uma lacuna de correção de cobrança.
  • Lote duplicado ou reenviado. Absorvido pela idempotência do backend; o reporter não deduplica. Não confie em entrega exatamente-uma-vez.
  • Retentativas esgotadas. O lote daquele backend é descartado e registrado em nível de erro. Um retorno normal de report() ou flush() nunca implica entrega.
  • Encerramento do processo antes do flush. O buffer é apenas em memória. Um crash, ou um encerramento sem um handler de shutdown registrado, perde as entradas em buffer.
  • Incompatibilidade de modelo de worker. Implantações PHP-FPM chamam registerShutdownFlush() uma vez no bootstrap para que o restante seja descarregado no fim da requisição. Workers de longa duração (Octane, worker do Symfony, worker de fila) devem, em vez disso, fazer flush em um temporizador periódico; caso contrário, as entradas se acumulam até o processo do worker encerrar.
  • $bufferSize abaixo de 1. Viola o contrato documentado positive-int; o resultado observável é um flush a cada chamada de record().
  • Metadados sensíveis. $metadata tem formato livre e pode carregar contexto operacional sensível. Armazenamento, retenção e controle de acesso são responsabilidade do operador do backend.
  • Falha de entrega do Pushgateway. Uma resposta não-2xx levanta PrometheusPushgatewayException carregando o status HTTP e o corpo da resposta; uma falha de transporte PSR-18 é encapsulada no mesmo tipo de exceção. O laço de retentativa e isolamento do reporter absorve ambos.
  • Sonda de saúde. PrometheusMeteringBackend::isHealthy() emite um GET contra <pushgatewayUrl>/-/healthy e retorna true apenas em HTTP 200. Qualquer erro de transporte retorna false; a sonda nunca lança exceção.
  • Valores de rótulo hostis. Caracteres de barra invertida, aspas duplas e quebra de linha em valores de operação ou tenant são escapados na emissão, de modo que um valor de rótulo não possa injetar linhas de exposição adicionais nem corromper o bloco de rótulos.
  • Modo FIPS. O coletor e o reporter não realizam nenhuma operação criptográfica e não têm comportamento específico de FIPS. Um backend que assina ou criptografa em trânsito herda a postura FIPS do provedor de criptografia do seu host.

Nenhum padrão externo rege o contrato em processo do coletor, do reporter ou do backend; não há especificação normativa a citar, então esta página não carrega nenhuma citação RAG, por design. O backend Prometheus emite o formato de exposição de texto do Prometheus e faz push com Content-Type text/plain; version=0.0.4; esse formato é uma convenção do ecossistema, e não um padrão ISO ou IETF, e a afirmação está fundamentada no código-fonte do produto. A NextPDF não faz nenhuma afirmação de conformidade ou certificação para esta superfície.

  • Todas as classes declaram strict_types=1 e são final; MeterEntry é final readonly com propriedades públicas promovidas. Tipos de argumento incompatíveis levantam um TypeError do PHP no chamador.
  • As classes do módulo carregam uma anotação de pacote @since de 2.1.0; PrometheusPushgatewayException carrega @since 3.2.0.
  • O logger do reporter usa por padrão um NullLogger PSR-3. Injete um logger real em produção, ou os lotes descartados não deixam rastro.
  • Teste unitário: implemente um fake MeteringBackendInterface e construa valores MeterEntry diretamente. O backend Prometheus recebe abstrações PSR-18/PSR-17, então um cliente HTTP mock exercita todo o caminho de push offline.
  • Testes de limite recomendados: buffer exatamente em $bufferSize, flush reentrante, flush de buffer vazio, um backend falhando enquanto um segundo tem sucesso e registro de esgotamento de retentativas.
  • Os implementadores de backend lançam RuntimeException (ou uma subclasse) em falha de entrega; o reporter a absorve. Respeite o requisito de idempotência antes de adicionar mais retentativas upstream.

Esta página documenta apenas o comportamento observável externamente e a superfície de API pública suportada. Caminhos de namespace internos, classes auxiliares, tabelas de mecanismo, nomes de arquivo de runbook e prefixos de tíquete estão fora do escopo.