Contracts / Наблюдаемость
Домен наблюдаемости определяет контракты, раскрывающие состояние движка во время выполнения: ContextAwareExceptionInterface — для структурированного контекста ошибок, SpectrumInterface — для необязательного сопроцесса ускорения, JobNotificationInterface — для потокового прогресса заданий, а перечисление DegradationPolicy — для поведения при потере возможностей.
Установка
Заголовок раздела «Установка»composer require nextpdf/core:^3Концептуальный обзор
Заголовок раздела «Концептуальный обзор»ContextAwareExceptionInterface — диагностический контракт. Его реализует каждое доменное исключение NextPDF. Любое перехваченное исключение NextPDF можно привести к этому контракту, чтобы получить структурированный контекст для инструмента мониторинга производительности приложений (APM), конвейера логирования или системы отчётов об ошибках. Контекст представляет собой ассоциативный массив с ключами в snake_case и только примитивными значениями. Вложенных объектов в нём нет. Поэтому он предсказуемо сериализуется в полезную нагрузку JavaScript Object Notation (JSON) или APM. Чтобы восстановить диагностические данные, разбирать сообщение исключения не нужно. Контракт имеет статус stable начиная с версии 3.1.0.
SpectrumInterface — контракт для необязательного сопроцесса ускорения. Spectrum выполняет работу параллельно на центральном процессоре (CPU), перенося обнаружение оборудования, разбор Portable Document Format (PDF) и сжатие изображений в локальный сопроцесс. Контракт сообщает о доступности через предохранитель (circuit breaker), поэтому частые проверки работоспособности не усиливают сбой, если сопроцесс недоступен. Он зондирует возможности оборудования и кэширует результат, раскрывает активный бюджет ресурсов и предоставляет общий транспорт запросов для модулей более высокого уровня. Движок работает без сопроцесса. Контракт делает ускорение внедряемой опцией, а не жёсткой зависимостью. JobNotificationInterface передаёт типизированные события заданий из конечной точки server-sent-events сопроцесса в виде генератора. Генератор останавливается, когда поступает терминальное событие или закрывается поток.
DegradationPolicy — перечисление, задающее поведение при потере возможностей. Когда возможность деградирует, политика в зависимости от степени влияния решает: выбросить исключение, выдать предупреждение или собрать данные без уведомления. Strict выбрасывает исключение, если влияние связано с риском несоответствия требованиям, семантической потерей или блокировкой. Используйте её в регулируемой среде, где корректность выходных данных обязательна. Balanced — значение по умолчанию — выдаёт структурированные предупреждения и продолжает работу при ограниченной деградации, а исключение выбрасывает только при блокирующем влиянии. Используйте её для большинства промышленных развёртываний. Permissive молча собирает все события и никогда не выбрасывает исключение. Используйте её для режима предпросмотра или черновика, где приемлемы выходные данные по принципу “насколько возможно”. Типы SpectrumInterface, JobNotificationInterface и DegradationPolicy имеют статус experimental. Их гарантия совместимости слабее, чем у ContextAwareExceptionInterface.
Поверхность API
Заголовок раздела «Поверхность API»| Тип | Вид | Ключевые члены | Стабильность | С версии |
|---|---|---|---|---|
ContextAwareExceptionInterface | interface | getContext(): array<string, mixed> | stable (стабильный) | 3.1.0 |
SpectrumInterface | interface | isAvailable(), probe(), getBudget(), request() | experimental (экспериментальный) | 2.1.0 |
JobNotificationInterface | interface | streamEvents(string): Generator<int, JobEvent> | experimental (экспериментальный) | 2.2.0 |
DegradationPolicy | enum (string) | Strict, Balanced, Permissive | experimental (экспериментальный) | 2.3.0 |
getContext() возвращает только примитивы или списки примитивов. streamEvents() выдаёт объекты JobEvent до терминального события. SpectrumInterface::request() возвращает необработанное тело ответа как string. probe() возвращает HardwareReport, а getBudget() возвращает SpectrumBudget.
Пример кода — быстрый старт
Заголовок раздела «Пример кода — быстрый старт»<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\ContextAwareExceptionInterface;use Psr\Log\LoggerInterface;
/** * Log a NextPDF exception with its structured context. * * @param \Throwable $e A caught exception. * @param LoggerInterface $logger A PSR-3 logger. */function logWithContext(\Throwable $e, LoggerInterface $logger): void{ if ($e instanceof ContextAwareExceptionInterface) { $logger->error($e->getMessage(), $e->getContext());
return; }
$logger->error($e->getMessage());}Структурированный контекст попадает в запись лога без разбора сообщения.
Пример кода — продакшен
Заголовок раздела «Пример кода — продакшен»<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\DegradationPolicy;use NextPDF\Contracts\SpectrumInterface;use Psr\Log\LoggerInterface;
final readonly class AcceleratedParseService{ public function __construct( private ?SpectrumInterface $spectrum, private DegradationPolicy $policy, private LoggerInterface $logger, ) {}
/** * Send a parse batch to the sidecar when healthy, otherwise fall back. * * @param list<array{id: string, data: string}> $documents PDF binaries with caller IDs. * * @return string Raw sidecar response body; decode with a batch-result parser. */ public function parse(array $documents): string { if ($this->spectrum?->isAvailable() === true) { return $this->spectrum->request( 'POST', '/v1/parse', json: ['documents' => $documents], scope: ['parse'], ); }
if ($this->policy === DegradationPolicy::Strict) { throw new \RuntimeException('Accelerator required under strict policy.'); }
$this->logger->info('Accelerator unavailable; using PHP fallback.');
return $this->phpFallback($documents); }
/** @param list<array{id: string, data: string}> $documents @return string */ private function phpFallback(array $documents): string { // Pure-PHP parse path omitted for brevity. return ''; }}SpectrumInterface, допускающий значение null, делает ускорение необязательным. Контракт раскрывает один транспортный метод — request(), который возвращает необработанное тело ответа как string. Парсер более высокого уровня превращает это тело в NextPDF\Accelerator\BatchResult. Конкретный SpectrumClient добавляет типизированные вспомогательные методы, такие как parseBatch(), которые оборачивают request() и напрямую возвращают BatchResult. Эти методы не входят в зафиксированный контракт. Политика деградации решает, является ли отсутствие сопроцесса фатальным.
Граничные случаи и подводные камни
Заголовок раздела «Граничные случаи и подводные камни»- Не каждый
\Throwableявляется исключением NextPDF. Прежде чем вызыватьgetContext(), проверяйтеinstanceof ContextAwareExceptionInterface. - По контракту
getContext()возвращает только примитивы. Ожидать вложенные объекты нельзя: контракт гарантирует значения, безопасные для JSON. SpectrumInterface::isAvailable()работает через предохранитель и безопасен для частого вызова, но результатtrue— это проверка на конкретный момент времени. Обрабатывайте ситуацию, когда сопроцесс отключается между проверкой и вызовом.JobNotificationInterface::streamEvents()— генератор. Повторная итерация по нему не воспроизводит события заново. Обрабатывайте его один раз.DegradationPolicy::Permissiveникогда не выбрасывает исключение. В этом режиме деградация, влияющая на соответствие требованиям, проходит без уведомления. Не используйте его для регулируемых выходных данных.
Производительность
Заголовок раздела «Производительность»Контракты наблюдаемости добавляют пренебрежимо малые накладные расходы. getContext() возвращает заранее подготовленный массив. isAvailable() — это кэшированная проверка работоспособности через предохранитель. Контракт требует, чтобы реализации кэшировали результат зондирования не менее 30 секунд, чтобы горячий путь не вызывал сопроцесс повторно. streamEvents() ограничен частотой событий сопроцесса, а не движком. Значение performance_budget в 1500 мс реального времени и 64 МБ пикового потребления относится к базовой работе, которую наблюдают контракты, а не к самим контрактам. Профиль воспроизводимости — structural. Потоки событий и контексты исключений содержат временные метки. В этих полях два запуска различаются, но структура остаётся идентичной.
Замечания по безопасности
Заголовок раздела «Замечания по безопасности»Структурированный контекст исключения становится источником утечки данных, если содержит секреты. Контракт ограничивает контекст примитивами, что снижает риск случайной утечки объектов. Тем не менее вы обязаны очищать конфиденциальные значения до того, как контекст попадёт в приёмник логов. Это требование безопасной телеметрии в политике логирования проекта. Сопроцесс ускорения — это отдельный процесс, доступ к которому осуществляется по транспорту. Метод запроса передаёт утверждения области (scope) для авторизации. Вы обязаны рассматривать границу сопроцесса как границу доверия. Политика деградации, установленная в Permissive, может замаскировать значимую для безопасности потерю возможностей. Используйте Strict там, где корректность выходных данных является мерой контроля. Рассматривайте контекст исключений, события заданий и ответы сопроцесса как данные, которые могут быть записаны в лог, и очищайте их соответствующим образом.
Соответствие требованиям
Заголовок раздела «Соответствие требованиям»Эта страница не содержит прямых нормативных утверждений. Контракты наблюдаемости раскрывают состояние движка и не реализуют стандартизированный протокол, на пункты которого движок должен ссылаться. Упомянутые выше обязательства по безопасной телеметрии и очистке логов вытекают из внутренней политики логирования проекта, а не из внешнего стандарта. Когда наблюдаемая операция сама стандартизирована — подпись, документ PDF/A — её соответствие требованиям задокументировано на странице подписания или извлечения.
Смотрите также
Заголовок раздела «Смотрите также»- Контракты: 41 публичный интерфейс (SPI) — обзор SPI и уровни стабильности.
- Наблюдаемость — модуль состояния во время выполнения, раскрываемого этими контрактами.
- Accelerator — клиент сопроцесса Spectrum, работающий через
SpectrumInterface. - Exception — исключения, реализующие
ContextAwareExceptionInterface. - Производительность — бюджеты, в рамках которых выполняется наблюдаемая работа.