Enterprise 版本
Metering — 深入參考
NextPDF\Enterprise\Metering 命名空間提供協調層級的用量計量,用於帳務可觀察性與稽核。公開介面共六個符號:MeterCollector、MeterEntry、MeteringReporter、MeteringBackendInterface、PrometheusMeteringBackend,以及 PrometheusPushgatewayException。收集器會在記憶體中緩衝不可變項目,並以批次沖刷。回報器會把每個批次扇出到一個或多個後端,並具備逐後端的重試與失敗隔離。計量是盡力而為且非致命的:計量後端的中斷會降低可觀察性,但絕不會影響文件處理。此串流並非配額強制的權威來源。工作流層級的指南請參閱 Metering。
可用性與授權
標題為「可用性與授權」的區段此能力隨 NextPDF Enterprise(nextpdf/enterprise)提供,並以 Enterprise 層級的授權封套啟用。未持有該權利的部署不會載入此能力的類別。比較版本並取得授權。
Metering 是一個基礎 Enterprise 能力,只要安裝 Enterprise 套件即可使用;沒有獨立的逐功能旗標。NextPDF Core(Apache-2.0)與 NextPDF Pro 沒有收集器、回報器或後端介面;此合約僅隨 nextpdf/enterprise 提供。
公開 API 介面
標題為「公開 API 介面」的區段| 符號 | 參數 | 預設行為 | 回傳 | 拋出或失敗於 | 備註 |
|---|---|---|---|---|---|
MeterCollector::__construct | MeteringReporter $reporter、int $bufferSize = 100 | 建立一個帶有空記憶體緩衝的收集器 | 新的 MeterCollector | 不拋出 | $bufferSize 文件記載為 positive-int |
MeterCollector::record | string $operation、int $count、string $tenantId、string $licenseId、int $pagesProcessed = 0、float $durationMs = 0.0、array $metadata = [] | 附加一個以當前時間戳記的不可變 MeterEntry;當緩衝達到 $bufferSize 時自動沖刷 | void | 不拋出;自動沖刷委派給回報器,而回報器絕不拋出 | 時間戳於記錄當下取得 |
MeterCollector::flush | — | 將所有緩衝的項目交給回報器;空緩衝為無操作 | void | 不拋出;後端失敗由回報器吸收 | 交付前先換出緩衝;可重入安全 |
MeterCollector::bufferCount | — | 回傳緩衝項目的數量 | int<0, max> | 不拋出 | 診斷與反壓決策 |
MeterCollector::registerShutdownFlush | — | 透過 register_shutdown_function 註冊 flush() | void | 不拋出 | 在 PHP-FPM 部署中於 bootstrap 時呼叫一次 |
MeterEntry::__construct | string $operation、int $count、DateTimeImmutable $timestamp、string $tenantId、string $licenseId、int $pagesProcessed = 0、float $durationMs = 0.0、array $metadata = [] | 逐字儲存所提供的值 | 新的 MeterEntry | 未宣告 @throws;在 strict_types 下若參數型別不符,PHP 會拋出 TypeError | final readonly;全部八個提升屬性皆為 public |
MeteringReporter::__construct | list<MeteringBackendInterface> $backends、int $maxRetries = 2、LoggerInterface $logger = new NullLogger() | 驗證並儲存後端清單 | 新的 MeteringReporter | 當 $backends 為空時拋出 InvalidArgumentException | $maxRetries 計算每個後端的總交付嘗試次數 |
MeteringReporter::report | list<MeterEntry> $entries | 獨立地將批次交付給每個後端,並具逐後端重試 | void | 不拋出;嘗試用盡會以 error 等級記錄並丟棄該後端的批次 | 空清單為無操作 |
MeteringBackendInterface::report | list<MeterEntry> $entries | 將批次交付給後端 | void | 當後端無法連線時拋出 RuntimeException | 實作必須具冪等性(以 timestamp + operation + tenantId 去重) |
MeteringBackendInterface::isHealthy | — | 可連線性探針 | bool | 未宣告 @throws | 僅供診斷;回報器不以此為閘門 |
MeteringBackendInterface::backendName | — | 診斷用的後端名稱 | non-empty-string | 未宣告 @throws | 例如 "prometheus"、"billing-api"、"null" |
PrometheusMeteringBackend::__construct | ClientInterface $httpClient、RequestFactoryInterface $requestFactory、StreamFactoryInterface $streamFactory、string $pushgatewayUrl、string $jobName = 'nextpdf_metering' | 設定一個 Pushgateway 推送目標 | 新的 PrometheusMeteringBackend | 不拋出 | 注入 PSR-18 用戶端與 PSR-17 工廠 |
PrometheusMeteringBackend::report | list<MeterEntry> $entries | 依 operation 與 tenant 序列彙整批次,並將呈現文字 POST 到 <pushgatewayUrl>/metrics/job/<jobName> | void | 在非 2xx 狀態或 PSR-18 傳輸失敗時拋出 PrometheusPushgatewayException | 空清單為無操作 |
PrometheusMeteringBackend::isHealthy | — | 探測 Pushgateway 健康端點;僅在 HTTP 200 時回傳 true | bool | 不拋出;任何失敗回傳 false | 唯讀的 GET 探針 |
PrometheusMeteringBackend::backendName | — | 回傳 "prometheus" | non-empty-string | 不拋出 | 常數 |
PrometheusPushgatewayException | — | 表示一次失敗的 Pushgateway 交付 | — | 即為該 throwable | final;繼承 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 {}MeterEntry 的 public readonly 屬性
| 屬性 | 型別 | 意義 |
|---|---|---|
$operation | non-empty-string | 操作類型,例如 "parse"、"compress"、"embed"、"rag_query" |
$count | positive-int | 所消耗的單位數量 |
$timestamp | DateTimeImmutable | 操作發生的時間;收集器於記錄當下戳記 |
$tenantId | non-empty-string | 租戶識別碼 |
$licenseId | non-empty-string | 授權識別碼 |
$pagesProcessed | int<0, max> | 已處理的 PDF 頁數;非 PDF 操作為 0 |
$durationMs | float | 操作時長(毫秒) |
$metadata | array<string, mixed> | 自由格式、特定於操作的中繼資料 |
行為合約
標題為「行為合約」的區段MeterCollector::record()會建構一個不可變的MeterEntry,以當前時間為其戳記,並將其附加到記憶體緩衝。當緩衝達到$bufferSize個項目時,收集器會自動沖刷。flush()具冪等性且可重入安全。空緩衝為無操作。在批次被交給回報器之前,緩衝會先被換出,因此一次可重入的沖刷不會重複送出。MeteringReporter在後端清單為空時拒絕建構。該InvalidArgumentException是收集器/回報器路徑上唯一的例外。MeteringReporter::report()會把每個批次獨立交付給每個後端。一個失敗的後端絕不會阻止另一個後端收到相同的批次。$maxRetries計算每個後端的總交付嘗試次數;預設值2代表一次初始嘗試加上一次重試。每次失敗的嘗試都會以 warning 等級記錄後端名稱、嘗試次數與項目數。- 當某個後端的最後一次嘗試失敗時,回報器會另外以 error 等級連同被丟棄的項目數一起記錄,然後繼續往下。它絕不會從
report()拋出例外,因此呼叫端不可從一次正常回傳推斷交付已完成。 - 後端必須具冪等性。介面合約要求以 timestamp、operation 與 tenant 識別碼為鍵進行去重。回報器本身不去重。
PrometheusMeteringBackend::report()會把批次彙整成逐 operation、逐 tenant 的序列,並以 Content-Typetext/plain; version=0.0.4將 Prometheus 文字呈現 POST 到<pushgatewayUrl>/metrics/job/<jobName>。預設的 job 名稱是nextpdf_metering。- 被推送的酬載承載三個計數器——
nextpdf_operations_total、nextpdf_pages_processed_total與nextpdf_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且為final;MeterEntry是final readonly,並帶有提升的 public 屬性。參數型別不符會在呼叫端引發 PHPTypeError。 - 模組類別帶有套件
@since註解2.1.0;PrometheusPushgatewayException帶有@since3.2.0。 - 回報器的記錄器預設為 PSR-3 的
NullLogger。請在生產環境注入一個真正的記錄器,否則被丟棄的批次不會留下任何痕跡。 - 單元測試:實作一個假的
MeteringBackendInterface,並直接建構MeterEntry值。Prometheus 後端接受 PSR-18/PSR-17 抽象,因此一個模擬的 HTTP 用戶端即可離線演練完整的推送路徑。 - 建議的邊界測試:緩衝恰好達到
$bufferSize、可重入沖刷、空緩衝沖刷、一個後端失敗而第二個成功,以及重試用盡的記錄。 - 後端實作者在交付失敗時拋出
RuntimeException(或其子類別);回報器會吸收它。在上游加入更多重試之前,請遵守冪等性要求。
發布邊界
標題為「發布邊界」的區段本頁僅記載外部可觀察的行為與受支援的公開 API 介面。內部命名空間路徑、輔助類別、機制表格、runbook 檔名,以及工單前綴皆不在範圍內。
另請參閱
標題為「另請參閱」的區段- Metering — NextPDF Enterprise — 能力頁面:工作流、設定與實作的部署範例。
- Billing — 深入參考 — 方案層級、超額語意與警示階梯。
- SaaS — 深入參考 — 多租戶協調介面。
- Licensing — 深入參考 — 啟用 Enterprise 能力的授權封套。