Enterprise エディション
Metering — 詳細リファレンス
NextPDF\Enterprise\Metering 名前空間は、課金の可視性と監査のためのオーケストレーションレベルの使用量計測を提供します。パブリックサーフェスは 6 つのシンボル、MeterCollector、MeterEntry、MeteringReporter、MeteringBackendInterface、PrometheusMeteringBackend、および PrometheusPushgatewayException です。コレクターはイミュータブルなエントリをメモリ内にバッファリングし、バッチ単位でフラッシュします。レポーターは各バッチを 1 つ以上のバックエンドへ、バックエンドごとのリトライと失敗の分離を伴ってファンアウトします。計測はベストエフォートかつ非致命的です。計測バックエンドの障害は可観測性を低下させますが、ドキュメント処理を低下させることは決してありません。このストリームはクォータ強制の権威的ソースではありません。ワークフローレベルのガイドについては、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 = [] | 現在時刻をスタンプした 1 件のイミュータブルな MeterEntry を追加。バッファが $bufferSize に達すると自動フラッシュ | void | スローしない。自動フラッシュはレポーターに委譲され、レポーターは決してスローしない | タイムスタンプはレコード時に取得 |
MeterCollector::flush | — | バッファされた全エントリをレポーターに引き渡す。空のバッファはノーオペレーション | void | スローしない。バックエンドの失敗はレポーターが吸収 | 引き渡し前にバッファをスワップアウト。再入可能で安全 |
MeterCollector::bufferCount | — | バッファされたエントリ数を返す | int<0, max> | スローしない | 診断とバックプレッシャーの判断 |
MeterCollector::registerShutdownFlush | — | register_shutdown_function 経由で flush() を登録 | void | スローしない | PHP-FPM デプロイメントではブートストラップ時に一度呼び出す |
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。昇格された 8 つのプロパティはすべて public |
MeteringReporter::__construct | list<MeteringBackendInterface> $backends, int $maxRetries = 2, LoggerInterface $logger = new NullLogger() | バックエンドリストを検証して格納 | 新しい MeteringReporter | $backends が空の場合 InvalidArgumentException | $maxRetries はバックエンドごとの総配信試行回数を数える |
MeteringReporter::report | list<MeterEntry> $entries | バッチを各バックエンドに独立して配信し、バックエンドごとにリトライ | void | スローしない。試行を使い果たすとエラーレベルでログし、そのバックエンドのバッチをドロップ | 空のリストはノーオペレーション |
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 | バッチを操作とテナントのシリーズごとに集約し、提示テキストを <pushgatewayUrl>/metrics/job/<jobName> へ POST | void | 非 2xx ステータスまたは PSR-18 トランスポート障害で PrometheusPushgatewayException | 空のリストはノーオペレーション |
PrometheusMeteringBackend::isHealthy | — | Pushgateway のヘルスエンドポイントをプローブ。HTTP 200 の場合のみ true | bool | スローしない。いかなる失敗も false を返す | 読み取り専用の GET プローブ |
PrometheusMeteringBackend::backendName | — | "prometheus" を返す | non-empty-string | スローしない | 定数 |
PrometheusPushgatewayException | — | Pushgateway の配信失敗を通知 | — | スロー対象そのもの | 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()は 1 件のイミュータブルなMeterEntryを構築し、現在時刻をスタンプして、メモリ内バッファに追加します。バッファが$bufferSize件に達すると、コレクターは自動フラッシュします。flush()は冪等かつ再入可能で安全です。空のバッファはノーオペレーションです。バッチがレポーターに引き渡される前にバッファがスワップアウトされるため、再入可能なフラッシュが二重送信することはありません。MeteringReporterは空のバックエンドリストでの構築を拒否します。そのInvalidArgumentExceptionが、コレクター/レポーターのパスにおける唯一の例外です。MeteringReporter::report()は各バッチをすべてのバックエンドに独立して配信します。あるバックエンドの失敗が、別のバックエンドが同じバッチを受信するのを妨げることは決してありません。$maxRetriesはバックエンドごとの総配信試行回数を数えます。デフォルトの2は、最初の試行 1 回に加えてリトライ 1 回を意味します。失敗した試行はすべて、バックエンド名、試行番号、エントリ数を含む警告をログに記録します。- あるバックエンドの最終試行が失敗した場合、レポーターはさらにドロップされたエントリ数とともにエラーレベルでログを記録し、次へ進みます。
report()から決してスローしないため、呼び出し側は通常の戻り値から配信を推測してはなりません。 - バックエンドは冪等でなければなりません。インターフェイスのコントラクトは、タイムスタンプ、操作、テナント識別子をキーとする重複排除を要求します。レポーター自体は重複排除を行いません。
PrometheusMeteringBackend::report()はバッチを操作ごと・テナントごとのシリーズに集約し、Prometheus テキスト提示を Content-Typetext/plain; version=0.0.4で<pushgatewayUrl>/metrics/job/<jobName>へ POST します。デフォルトのジョブ名はnextpdf_meteringです。- プッシュされるペイロードは 3 つのカウンター —
nextpdf_operations_total、nextpdf_pages_processed_total、nextpdf_operation_duration_ms_total— を持ち、それぞれ操作とテナントでラベル付けされます。 - この計測ストリームは非権威的です。クォータ強制と権威的なコンピュート計測は、デプロイメントの別個の権威的な使用量の数値を利用し、このバッファを利用することは決してありません。オーケストレーション計測のギャップは可観測性のギャップであり、課金の正確性のギャップではありません。
エッジケースと障害モード
「エッジケースと障害モード」という見出しのセクション- 重複またはリプレイされたバッチ。 バックエンドの冪等性によって吸収されます。レポーターは重複排除を行いません。厳密に 1 回の配信に依存しないでください。
- 使い果たされたリトライ。 そのバックエンドのバッチはドロップされ、エラーレベルでログに記録されます。
report()またはflush()からの通常の戻り値が配信を意味することは決してありません。 - フラッシュ前のプロセス終了。 バッファはメモリ内のみです。クラッシュ、またはシャットダウンハンドラーを登録していない終了は、バッファされたエントリを失います。
- ワーカーモデルの不一致。 PHP-FPM デプロイメントは、リクエスト終了時に残りがフラッシュされるよう、ブートストラップ時に
registerShutdownFlush()を一度呼び出します。長時間実行ワーカー(Octane、Symfony ワーカー、キューワーカー)は、代わりに定期タイマーでフラッシュしなければなりません。そうしないと、ワーカープロセスが終了するまでエントリが蓄積されます。 $bufferSizeが1未満。 ドキュメント化されたpositive-intコントラクトに違反します。観測される結果は、record()呼び出しごとのフラッシュです。- 機微なメタデータ。
$metadataは自由形式であり、機微な操作コンテキストを保持する場合があります。保存、保持、アクセス制御はバックエンドオペレーターの責任です。 - Pushgateway の配信失敗。 非 2xx レスポンスは、HTTP ステータスとレスポンスボディを保持する
PrometheusPushgatewayExceptionを発生させます。PSR-18 トランスポート障害は同じ例外型でラップされます。レポーターのリトライと分離のループが両方を吸収します。 - ヘルスプローブ。
PrometheusMeteringBackend::isHealthy()は<pushgatewayUrl>/-/healthyに対して GET を発行し、HTTP 200 の場合のみtrueを返します。いかなるトランスポートエラーもfalseを返し、プローブは決してスローしません。 - 敵対的なラベル値。 操作またはテナントの値に含まれるバックスラッシュ、二重引用符、改行文字は出力時にエスケープされるため、ラベル値が追加の提示行を注入したり、ラベルブロックを破損させたりすることはできません。
- 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ちょうどのバッファ、再入可能なフラッシュ、空バッファのフラッシュ、1 つのバックエンドが失敗し 2 つ目が成功するケース、リトライ使い果たしのロギング。 - バックエンドの実装者は、配信失敗時に
RuntimeException(またはそのサブクラス)をスローします。レポーターがそれを吸収します。上流でさらにリトライを追加する前に、冪等性の要件を守ってください。
公開範囲の境界
「公開範囲の境界」という見出しのセクションこのページは、外部から観測可能な挙動とサポートされるパブリック API サーフェスのみを記述します。内部の名前空間パス、ヘルパークラス、メカニズムのテーブル、ランブックのファイル名、チケットのプレフィックスは対象外です。
- Metering — NextPDF Enterprise — 機能ページ。ワークフロー、構成、実践的なデプロイメント例。
- Billing — 詳細リファレンス — プランティア、超過分のセマンティクス、アラートの段階。
- SaaS — 詳細リファレンス — マルチテナントオーケストレーションのサーフェス。
- Licensing — 詳細リファレンス — Enterprise 機能を有効化するライセンスエンベロープ。