跳到內容
getnextpdf.com

Enterprise 版本

Metering — 深入參考

NextPDF\Enterprise\Metering 命名空間提供協調層級的用量計量,用於帳務可觀察性與稽核。公開介面共六個符號:MeterCollectorMeterEntryMeteringReporterMeteringBackendInterfacePrometheusMeteringBackend,以及 PrometheusPushgatewayException。收集器會在記憶體中緩衝不可變項目,並以批次沖刷。回報器會把每個批次扇出到一個或多個後端,並具備逐後端的重試與失敗隔離。計量是盡力而為且非致命的:計量後端的中斷會降低可觀察性,但絕不會影響文件處理。此串流並非配額強制的權威來源。工作流層級的指南請參閱 Metering

此能力隨 NextPDF Enterprisenextpdf/enterprise)提供,並以 Enterprise 層級的授權封套啟用。未持有該權利的部署不會載入此能力的類別。比較版本並取得授權

Metering 是一個基礎 Enterprise 能力,只要安裝 Enterprise 套件即可使用;沒有獨立的逐功能旗標。NextPDF Core(Apache-2.0)與 NextPDF Pro 沒有收集器、回報器或後端介面;此合約僅隨 nextpdf/enterprise 提供。

符號參數預設行為回傳拋出或失敗於備註
MeterCollector::__constructMeteringReporter $reporterint $bufferSize = 100建立一個帶有空記憶體緩衝的收集器新的 MeterCollector不拋出$bufferSize 文件記載為 positive-int
MeterCollector::recordstring $operationint $countstring $tenantIdstring $licenseIdint $pagesProcessed = 0float $durationMs = 0.0array $metadata = []附加一個以當前時間戳記的不可變 MeterEntry;當緩衝達到 $bufferSize 時自動沖刷void不拋出;自動沖刷委派給回報器,而回報器絕不拋出時間戳於記錄當下取得
MeterCollector::flush將所有緩衝的項目交給回報器;空緩衝為無操作void不拋出;後端失敗由回報器吸收交付前先換出緩衝;可重入安全
MeterCollector::bufferCount回傳緩衝項目的數量int<0, max>不拋出診斷與反壓決策
MeterCollector::registerShutdownFlush透過 register_shutdown_function 註冊 flush()void不拋出在 PHP-FPM 部署中於 bootstrap 時呼叫一次
MeterEntry::__constructstring $operationint $countDateTimeImmutable $timestampstring $tenantIdstring $licenseIdint $pagesProcessed = 0float $durationMs = 0.0array $metadata = []逐字儲存所提供的值新的 MeterEntry未宣告 @throws;在 strict_types 下若參數型別不符,PHP 會拋出 TypeErrorfinal readonly;全部八個提升屬性皆為 public
MeteringReporter::__constructlist<MeteringBackendInterface> $backendsint $maxRetries = 2LoggerInterface $logger = new NullLogger()驗證並儲存後端清單新的 MeteringReporter$backends 為空時拋出 InvalidArgumentException$maxRetries 計算每個後端的總交付嘗試次數
MeteringReporter::reportlist<MeterEntry> $entries獨立地將批次交付給每個後端,並具逐後端重試void不拋出;嘗試用盡會以 error 等級記錄並丟棄該後端的批次空清單為無操作
MeteringBackendInterface::reportlist<MeterEntry> $entries將批次交付給後端void當後端無法連線時拋出 RuntimeException實作必須具冪等性(以 timestamp + operation + tenantId 去重)
MeteringBackendInterface::isHealthy可連線性探針bool未宣告 @throws僅供診斷;回報器不以此為閘門
MeteringBackendInterface::backendName診斷用的後端名稱non-empty-string未宣告 @throws例如 "prometheus""billing-api""null"
PrometheusMeteringBackend::__constructClientInterface $httpClientRequestFactoryInterface $requestFactoryStreamFactoryInterface $streamFactorystring $pushgatewayUrlstring $jobName = 'nextpdf_metering'設定一個 Pushgateway 推送目標新的 PrometheusMeteringBackend不拋出注入 PSR-18 用戶端與 PSR-17 工廠
PrometheusMeteringBackend::reportlist<MeterEntry> $entries依 operation 與 tenant 序列彙整批次,並將呈現文字 POST 到 <pushgatewayUrl>/metrics/job/<jobName>void在非 2xx 狀態或 PSR-18 傳輸失敗時拋出 PrometheusPushgatewayException空清單為無操作
PrometheusMeteringBackend::isHealthy探測 Pushgateway 健康端點;僅在 HTTP 200 時回傳 truebool不拋出;任何失敗回傳 false唯讀的 GET 探針
PrometheusMeteringBackend::backendName回傳 "prometheus"non-empty-string不拋出常數
PrometheusPushgatewayException表示一次失敗的 Pushgateway 交付即為該 throwablefinal;繼承 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 {}

MeterEntry 的 public readonly 屬性

屬性型別意義
$operationnon-empty-string操作類型,例如 "parse""compress""embed""rag_query"
$countpositive-int所消耗的單位數量
$timestampDateTimeImmutable操作發生的時間;收集器於記錄當下戳記
$tenantIdnon-empty-string租戶識別碼
$licenseIdnon-empty-string授權識別碼
$pagesProcessedint<0, max>已處理的 PDF 頁數;非 PDF 操作為 0
$durationMsfloat操作時長(毫秒)
$metadataarray<string, mixed>自由格式、特定於操作的中繼資料
  • MeterCollector::record() 會建構一個不可變的 MeterEntry,以當前時間為其戳記,並將其附加到記憶體緩衝。當緩衝達到 $bufferSize 個項目時,收集器會自動沖刷。
  • flush() 具冪等性且可重入安全。空緩衝為無操作。在批次被交給回報器之前,緩衝會先被換出,因此一次可重入的沖刷不會重複送出。
  • MeteringReporter 在後端清單為空時拒絕建構。該 InvalidArgumentException 是收集器/回報器路徑上唯一的例外。
  • MeteringReporter::report() 會把每個批次獨立交付給每個後端。一個失敗的後端絕不會阻止另一個後端收到相同的批次。
  • $maxRetries 計算每個後端的總交付嘗試次數;預設值 2 代表一次初始嘗試加上一次重試。每次失敗的嘗試都會以 warning 等級記錄後端名稱、嘗試次數與項目數。
  • 當某個後端的最後一次嘗試失敗時,回報器會另外以 error 等級連同被丟棄的項目數一起記錄,然後繼續往下。它絕不會從 report() 拋出例外,因此呼叫端不可從一次正常回傳推斷交付已完成。
  • 後端必須具冪等性。介面合約要求以 timestamp、operation 與 tenant 識別碼為鍵進行去重。回報器本身不去重。
  • PrometheusMeteringBackend::report() 會把批次彙整成逐 operation、逐 tenant 的序列,並以 Content-Type text/plain; version=0.0.4 將 Prometheus 文字呈現 POST 到 <pushgatewayUrl>/metrics/job/<jobName>。預設的 job 名稱是 nextpdf_metering
  • 被推送的酬載承載三個計數器——nextpdf_operations_totalnextpdf_pages_processed_totalnextpdf_operation_duration_ms_total——每個都以 operation 與 tenant 標記。
  • 這個計量串流是非權威的。配額強制與權威的計算量計量消費的是該部署另外分開的權威用量數字,絕不是這個緩衝。協調計量中的缺口是可觀察性缺口,不是帳務正確性缺口。
  • 重複或重播的批次。 由後端的冪等性吸收;回報器不去重。請勿仰賴恰好一次(exactly-once)交付。
  • 重試用盡。 該後端的批次會被丟棄並以 error 等級記錄。report()flush() 的一次正常回傳絕不代表交付已完成。
  • 沖刷前行程結束。 緩衝僅存於記憶體。當機、或在未註冊關機處理器的情況下結束,都會遺失緩衝中的項目。
  • 工作者模型不符。 PHP-FPM 部署會在 bootstrap 時呼叫一次 registerShutdownFlush(),讓剩餘部分在請求結束時沖刷。長時間執行的工作者(Octane、Symfony worker、queue worker)則必須改以週期性計時器沖刷;否則項目會累積到工作者行程結束為止。
  • $bufferSize 小於 1 違反文件記載的 positive-int 合約;可觀察到的結果是每次 record() 呼叫都會沖刷。
  • 敏感中繼資料。 $metadata 是自由格式,且可能承載敏感的操作情境。儲存、保留與存取控制是後端操作者的責任。
  • Pushgateway 交付失敗。 非 2xx 回應會拋出承載 HTTP 狀態與回應主體的 PrometheusPushgatewayException;PSR-18 傳輸失敗則被包裝成相同的例外型別。回報器的重試與隔離迴圈會吸收兩者。
  • 健康探針。 PrometheusMeteringBackend::isHealthy() 會對 <pushgatewayUrl>/-/healthy 發出一個 GET,且僅在 HTTP 200 時回傳 true。任何傳輸錯誤都回傳 false;探針絕不拋出。
  • 惡意的標籤值。 operation 或 tenant 值中的反斜線、雙引號與換行字元會在輸出時被轉義,因此一個標籤值無法注入額外的呈現行或破壞標籤區塊。
  • FIPS 模式。 收集器與回報器不執行任何密碼學運算,也沒有任何 FIPS 特定行為。任何在傳輸中簽署或加密的後端,會繼承其主機密碼學提供者的 FIPS 態勢。

沒有任何外部標準規範這個行程內的收集器、回報器或後端合約;沒有任何規範性規格可引用,因此本頁依設計不帶任何 RAG 引用。Prometheus 後端會輸出 Prometheus 文字呈現格式,並以 Content-Type text/plain; version=0.0.4 推送;該格式是一項生態系慣例,而非 ISO 或 IETF 標準,此主張以產品原始碼為依據。NextPDF 對此介面不作任何一致性或認證聲明。

  • 所有類別都宣告 strict_types=1 且為 finalMeterEntryfinal readonly,並帶有提升的 public 屬性。參數型別不符會在呼叫端引發 PHP TypeError
  • 模組類別帶有套件 @since 註解 2.1.0PrometheusPushgatewayException 帶有 @since 3.2.0
  • 回報器的記錄器預設為 PSR-3 的 NullLogger。請在生產環境注入一個真正的記錄器,否則被丟棄的批次不會留下任何痕跡。
  • 單元測試:實作一個假的 MeteringBackendInterface,並直接建構 MeterEntry 值。Prometheus 後端接受 PSR-18/PSR-17 抽象,因此一個模擬的 HTTP 用戶端即可離線演練完整的推送路徑。
  • 建議的邊界測試:緩衝恰好達到 $bufferSize、可重入沖刷、空緩衝沖刷、一個後端失敗而第二個成功,以及重試用盡的記錄。
  • 後端實作者在交付失敗時拋出 RuntimeException(或其子類別);回報器會吸收它。在上游加入更多重試之前,請遵守冪等性要求。

本頁僅記載外部可觀察的行為與受支援的公開 API 介面。內部命名空間路徑、輔助類別、機制表格、runbook 檔名,以及工單前綴皆不在範圍內。