Перейти к содержимому
getnextpdf.com

Enterprise редакция

Metering — глубокий справочник

Пространство имён NextPDF\Enterprise\Metering предоставляет учёт потребления на уровне оркестрации для видимости биллинга и аудита. Публичная поверхность — шесть символов: MeterCollector, MeterEntry, MeteringReporter, MeteringBackendInterface, PrometheusMeteringBackend и PrometheusPushgatewayException. Сборщик буферизует неизменяемые записи в памяти и сбрасывает их пакетами. Репортёр веерно распределяет каждый пакет по одному или нескольким бэкендам с повторными попытками и изоляцией сбоев на каждый бэкенд. Учёт работает с наилучшим усилием и не фатален: сбой бэкенда учёта ухудшает наблюдаемость, но никогда не обработку документов. Этот поток не является авторитетным источником для навязывания квот. Руководство на уровне рабочего процесса см. в Metering.

Эта возможность поставляется в NextPDF Enterprise (nextpdf/enterprise) и активируется лицензионным конвертом уровня Enterprise. Развёртывание без этого права не загружает классы возможности. Сравнить редакции и получить лицензию.

Учёт — это базовая возможность Enterprise, доступная, как только установлен пакет Enterprise; отдельного флага на каждую функцию нет. В NextPDF Core (Apache-2.0) и NextPDF Pro нет поверхности сборщика, репортёра или бэкенда; контракт поставляется только в nextpdf/enterprise.

СимволПараметрыПоведение по умолчаниюВозвращаетВыбрасывает или завершается сПримечания
MeterCollector::__constructMeteringReporter $reporter, int $bufferSize = 100Создаёт сборщик с пустым буфером в памятиНовый MeterCollectorНе выбрасывает$bufferSize документирован как positive-int
MeterCollector::recordstring $operation, int $count, string $tenantId, string $licenseId, int $pagesProcessed = 0, float $durationMs = 0.0, array $metadata = []Добавляет одну неизменяемую MeterEntry с отметкой текущего времени; автоматически сбрасывает, когда буфер достигает $bufferSizevoidНе выбрасывает; автосброс делегирует репортёру, который никогда не выбрасываетМетка времени берётся в момент записи
MeterCollector::flushПередаёт все буферизованные записи репортёру; пустой буфер — no-opvoidНе выбрасывает; сбои бэкендов поглощаются репортёромБуфер выгружается до передачи; безопасен при повторном входе
MeterCollector::bufferCountВозвращает число буферизованных записейint<0, max>Не выбрасываетДиагностика и решения по обратному давлению
MeterCollector::registerShutdownFlushРегистрирует flush() через register_shutdown_functionvoidНе выбрасываетВызовите один раз при загрузке в развёртываниях PHP-FPM
MeterEntry::__constructstring $operation, int $count, DateTimeImmutable $timestamp, string $tenantId, string $licenseId, int $pagesProcessed = 0, float $durationMs = 0.0, array $metadata = []Сохраняет переданные значения без измененийНовый MeterEntryНет объявленного @throws; PHP вызывает TypeError при несоответствии типов аргументов под strict_typesfinal readonly; все восемь продвинутых свойств публичны
MeteringReporter::__constructlist<MeteringBackendInterface> $backends, int $maxRetries = 2, LoggerInterface $logger = new NullLogger()Проверяет и сохраняет список бэкендовНовый MeteringReporterInvalidArgumentException, когда $backends пуст$maxRetries считает общее число попыток доставки на каждый бэкенд
MeteringReporter::reportlist<MeterEntry> $entriesДоставляет пакет каждому бэкенду независимо, с повторами на каждый бэкендvoidНе выбрасывает; исчерпанные попытки логируются на уровне ошибки и отбрасывают пакет этого бэкендаПустой список — no-op
MeteringBackendInterface::reportlist<MeterEntry> $entriesДоставляет пакет бэкендуvoidRuntimeException, когда бэкенд недостижимРеализации ДОЛЖНЫ быть идемпотентны (дедупликация по timestamp + operation + tenantId)
MeteringBackendInterface::isHealthyЗонд достижимостиboolНет объявленного @throwsТолько диагностика; репортёр не опирается на него
MeteringBackendInterface::backendNameДиагностическое имя бэкендаnon-empty-stringНет объявленного @throwsНапример "prometheus", "billing-api", "null"
PrometheusMeteringBackend::__constructClientInterface $httpClient, RequestFactoryInterface $requestFactory, StreamFactoryInterface $streamFactory, string $pushgatewayUrl, string $jobName = 'nextpdf_metering'Настраивает push-цель PushgatewayНовый PrometheusMeteringBackendНе выбрасываетВнедряются клиент PSR-18 и фабрики PSR-17
PrometheusMeteringBackend::reportlist<MeterEntry> $entriesАгрегирует пакет по сериям «операция и арендатор» и отправляет POST с текстом экспозиции на <pushgatewayUrl>/metrics/job/<jobName>voidPrometheusPushgatewayException при статусе не 2xx или сбое транспорта PSR-18Пустой список — no-op
PrometheusMeteringBackend::isHealthyЗондирует health-эндпойнт Pushgateway; true только при HTTP 200boolНе выбрасывает; любой сбой возвращает falseGET-зонд только на чтение
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(): 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 {}

Публичные readonly-свойства MeterEntry

СвойствоТипЗначение
$operationnon-empty-stringТип операции, например "parse", "compress", "embed", "rag_query"
$countpositive-intЧисло потреблённых единиц
$timestampDateTimeImmutableКогда произошла операция; сборщик проставляет отметку в момент записи
$tenantIdnon-empty-stringИдентификатор арендатора
$licenseIdnon-empty-stringИдентификатор лицензии
$pagesProcessedint<0, max>Обработанные страницы PDF; 0 для операций не с PDF
$durationMsfloatДлительность операции в миллисекундах
$metadataarray<string, mixed>Произвольные метаданные, специфичные для операции
  • MeterCollector::record() создаёт одну неизменяемую MeterEntry, проставляет отметку текущего времени и добавляет её в буфер в памяти. Когда буфер достигает $bufferSize записей, сборщик автоматически сбрасывает.
  • flush() идемпотентен и безопасен при повторном входе. Пустой буфер — no-op. Буфер выгружается до передачи пакета репортёру, так что повторный сброс не может отправить дважды.
  • MeteringReporter отклоняет построение с пустым списком бэкендов. Это InvalidArgumentException — единственное исключение на пути сборщика/репортёра.
  • MeteringReporter::report() доставляет каждый пакет каждому бэкенду независимо. Сбойный бэкенд никогда не мешает другому бэкенду получить тот же пакет.
  • $maxRetries считает общее число попыток доставки на каждый бэкенд; значение по умолчанию 2 означает одну исходную попытку плюс один повтор. Каждая неудачная попытка логирует предупреждение с именем бэкенда, номером попытки и числом записей.
  • Когда финальная попытка для бэкенда проваливается, репортёр дополнительно логирует на уровне ошибки со счётчиком отброшенных записей и идёт дальше. Он никогда не выбрасывает из report(), поэтому вызывающие не должны делать вывод о доставке из обычного возврата.
  • Бэкенды ДОЛЖНЫ быть идемпотентны. Контракт интерфейса требует дедупликации по ключу из метки времени, операции и идентификатора арендатора. Сам репортёр не дедуплицирует.
  • PrometheusMeteringBackend::report() агрегирует пакет в серии по операции и арендатору и отправляет POST с текстовой экспозицией Prometheus на <pushgatewayUrl>/metrics/job/<jobName> с Content-Type text/plain; version=0.0.4. Имя задания по умолчанию — nextpdf_metering.
  • Отправленная полезная нагрузка несёт три счётчика — nextpdf_operations_total, nextpdf_pages_processed_total и nextpdf_operation_duration_ms_total — каждый с метками по операции и арендатору.
  • Этот поток учёта неавторитетен. Навязывание квот и авторитетный учёт вычислений потребляют отдельную авторитетную величину потребления развёртывания, а не этот буфер. Пробел в учёте оркестрации — это пробел наблюдаемости, а не пробел корректности биллинга.
  • Дублированный или воспроизведённый пакет. Поглощается идемпотентностью бэкенда; репортёр не дедуплицирует. Не полагайтесь на доставку строго один раз.
  • Исчерпанные повторные попытки. Пакет для этого бэкенда отбрасывается и логируется на уровне ошибки. Обычный возврат из report() или flush() никогда не подразумевает доставку.
  • Выход процесса до сброса. Буфер существует только в памяти. Аварийное завершение или выход без зарегистрированного обработчика завершения теряет буферизованные записи.
  • Несоответствие модели воркера. Развёртывания PHP-FPM вызывают registerShutdownFlush() один раз при загрузке, чтобы остаток сбрасывался в конце запроса. Долгоживущие воркеры (Octane, воркер Symfony, воркер очереди) должны вместо этого сбрасывать по периодическому таймеру; иначе записи накапливаются до выхода процесса воркера.
  • $bufferSize меньше 1. Нарушает документированный контракт positive-int; наблюдаемый результат — сброс при каждом вызове record().
  • Чувствительные метаданные. $metadata произвольны по форме и могут нести чувствительный контекст операции. Хранение, удержание и контроль доступа — ответственность оператора бэкенда.
  • Сбой доставки в Pushgateway. Ответ не 2xx вызывает PrometheusPushgatewayException с HTTP-статусом и телом ответа; сбой транспорта PSR-18 оборачивается в тот же тип исключения. Цикл повторов и изоляции репортёра поглощает оба.
  • Зонд работоспособности. PrometheusMeteringBackend::isHealthy() выполняет GET к <pushgatewayUrl>/-/healthy и возвращает true только при HTTP 200. Любая ошибка транспорта возвращает false; зонд никогда не выбрасывает.
  • Враждебные значения меток. Символы обратной косой черты, двойной кавычки и перевода строки в значениях операции или арендатора экранируются при выводе, так что значение метки не может внедрить дополнительные строки экспозиции или испортить блок меток.
  • Режим FIPS. Сборщик и репортёр не выполняют криптографических операций и не имеют поведения, специфичного для FIPS. Бэкенд, который подписывает или шифрует при передаче, наследует FIPS-позицию криптопровайдера своего хоста.

Никакой внешний стандарт не управляет контрактом внутрипроцессного сборщика, репортёра или бэкенда; нет нормативной спецификации для цитирования, поэтому эта страница по замыслу не несёт RAG-цитаты. Бэкенд Prometheus выдаёт текстовый формат экспозиции Prometheus и отправляет с Content-Type text/plain; version=0.0.4; этот формат — конвенция экосистемы, а не стандарт ISO или IETF, и утверждение основано на исходном коде продукта. NextPDF не делает никаких заявлений о соответствии или сертификации для этой поверхности.

  • Все классы объявляют strict_types=1 и являются final; MeterEntryfinal readonly с продвинутыми публичными свойствами. Несоответствие типов аргументов вызывает PHP TypeError в вызывающем коде.
  • Классы модуля несут пакетную аннотацию @since 2.1.0; PrometheusPushgatewayException несёт @since 3.2.0.
  • Логгер репортёра по умолчанию — PSR-3 NullLogger. Внедрите реальный логгер в продакшене, иначе отброшенные пакеты не оставляют следа.
  • Модульное тестирование: реализуйте поддельный MeteringBackendInterface и создавайте значения MeterEntry напрямую. Бэкенд Prometheus принимает абстракции PSR-18/PSR-17, так что мок HTTP-клиента прогоняет весь путь push офлайн.
  • Рекомендуемые граничные тесты: буфер ровно на $bufferSize, повторный сброс, сброс пустого буфера, сбой одного бэкенда при успехе второго и логирование исчерпания повторов.
  • Реализаторы бэкендов выбрасывают RuntimeException (или подкласс) при сбое доставки; репортёр его поглощает. Соблюдайте требование идемпотентности, прежде чем добавлять дополнительные повторы выше по потоку.

Эта страница документирует только внешне наблюдаемое поведение и поддерживаемую публичную поверхность API. Внутренние пути пространств имён, вспомогательные классы, таблицы механизмов, имена файлов руководств по эксплуатации и префиксы тикетов вне области действия.