Contracts / Observabilidade
Visão geral
Seção intitulada “Visão geral”O domínio de observabilidade define os contracts que expõem o estado de runtime do engine: ContextAwareExceptionInterface para contexto de erro estruturado, SpectrumInterface para o sidecar de aceleração opcional, JobNotificationInterface para progresso de jobs em fluxo, e o enum DegradationPolicy para o comportamento em caso de perda de capacidade.
Instalação
Seção intitulada “Instalação”composer require nextpdf/core:^3Visão conceitual
Seção intitulada “Visão conceitual”ContextAwareExceptionInterface é o contract de diagnóstico. Toda exceção de domínio do NextPDF implementa esse contract. Você pode fazer o cast de qualquer exceção do NextPDF capturada para este contract e recuperar contexto estruturado para uma ferramenta de Application Performance Monitoring (APM), um pipeline de logging ou um reportador de erros. O contexto é um array associativo com chaves em snake_case e somente valores primitivos. Ele não contém objetos aninhados. Como resultado, ele é serializado de forma previsível para um payload em JavaScript Object Notation (JSON) ou um payload de APM. Você não precisa fazer o parsing de uma mensagem de exceção para recuperar dados de diagnóstico. Esse contract está stable desde a 3.1.0.
SpectrumInterface é o contract do sidecar de aceleração opcional. O Spectrum executa o trabalho em paralelo na central processing unit (CPU), transferindo a detecção de hardware, o parsing de Portable Document Format (PDF) e a compressão de imagens para um processo sidecar local. O contract informa a disponibilidade por trás de um circuit breaker, para que health checks frequentes não amplifiquem uma falha quando o sidecar está fora do ar. Ele sonda as capacidades de hardware e armazena o resultado em cache. Também expõe o orçamento de recursos ativo e fornece um transporte de requisições genérico para módulos de nível mais alto. O engine funciona sem o sidecar. O contract torna a aceleração uma opção injetável, e não uma dependência rígida. JobNotificationInterface transmite eventos de job tipados a partir do endpoint de server-sent-events do sidecar como um generator. O generator para quando um evento terminal chega ou o fluxo é encerrado.
DegradationPolicy é o enum de comportamento para perda de capacidade. Quando uma capacidade se degrada, a política decide, com base no impacto, se lança uma exceção, emite um aviso ou coleta silenciosamente. Strict lança uma exceção quando o impacto é um risco de compliance, uma perda semântica ou um bloqueio. Use-a em um ambiente regulado em que a correção da saída seja obrigatória. Balanced, o padrão, emite avisos estruturados e continua diante de uma degradação limitada, lançando uma exceção apenas em caso de impacto bloqueante. Use-a na maioria das implantações em produção. Permissive coleta todos os eventos silenciosamente e nunca lança uma exceção. Use-a no modo de preview ou rascunho, em que uma saída de melhor esforço seja aceitável. Os tipos SpectrumInterface, JobNotificationInterface e DegradationPolicy são experimental. A promessa de compatibilidade desses tipos é mais fraca do que a de ContextAwareExceptionInterface.
Superfície da API
Seção intitulada “Superfície da API”| Tipo | Categoria | Membros principais | Estabilidade | Desde |
|---|---|---|---|---|
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() retorna apenas primitivos ou listas de primitivos. streamEvents() produz objetos JobEvent até um evento terminal. SpectrumInterface::request() retorna o corpo bruto da resposta como uma string. probe() retorna um HardwareReport, e getBudget() retorna um SpectrumBudget.
Exemplo de código — Início rápido
Seção intitulada “Exemplo de código — Início rápido”<?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());}O contexto estruturado vai para o registro de log sem exigir o parsing da mensagem.
Exemplo de código — Produção
Seção intitulada “Exemplo de código — Produção”<?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 ''; }}O SpectrumInterface anulável torna a aceleração opcional. O contract expõe um método de transporte, request(), que retorna o corpo bruto da resposta como uma string. Um parser de nível mais alto transforma esse corpo em um NextPDF\Accelerator\BatchResult. O SpectrumClient concreto adiciona helpers tipados, como parseBatch(), que encapsulam request() e retornam BatchResult diretamente. Esses helpers não fazem parte do contract congelado. A política de degradação decide se a ausência de um sidecar é fatal.
Casos extremos e pegadinhas
Seção intitulada “Casos extremos e pegadinhas”- Nem todo
\Throwableé uma exceção do NextPDF. Proteja cominstanceof ContextAwareExceptionInterfaceantes de chamargetContext(). getContext()retorna apenas primitivos por contract. Se você espera objetos aninhados, essa suposição está errada; o contract garante valores seguros para JSON.SpectrumInterface::isAvailable()roda por trás de um circuit breaker e é seguro chamar com frequência, mas um resultadotrueé uma verificação pontual. Trate a possibilidade de o sidecar cair entre a verificação e a chamada.JobNotificationInterface::streamEvents()é um generator. Iterá-lo duas vezes não repete os eventos. Consuma-o apenas uma vez.DegradationPolicy::Permissivenunca lança uma exceção. Nesse modo, uma degradação que afeta a compliance passa silenciosamente. Não a use para saída regulada.
Desempenho
Seção intitulada “Desempenho”Os contracts de observabilidade adicionam um custo desprezível. getContext() retorna um array pré-construído. isAvailable() é uma sonda de saúde em cache e protegida por circuit breaker. O contract exige que as implementações mantenham o resultado da sonda em cache por pelo menos 30 segundos, para que um caminho crítico não chame o sidecar repetidamente. streamEvents() é limitado pela taxa de eventos do sidecar, não pelo engine. O performance_budget de 1500 ms de tempo de parede e 64 MB de pico é definido pelo trabalho subjacente que os contracts observam, não pelos próprios contracts. O perfil de reprodutibilidade é structural. Os fluxos de eventos e os contextos de exceção incluem timestamps. Duas execuções diferem nesses campos, enquanto a estrutura permanece idêntica.
Notas de segurança
Seção intitulada “Notas de segurança”O contexto estruturado de exceção é uma superfície de exfiltração de dados caso carregue segredos. O contract restringe o contexto a primitivos, o que limita o vazamento acidental de objetos. Ainda assim, você deve sanitizar valores sensíveis antes que o contexto chegue a um destino de log. Essa é a obrigação de telemetria segura na política de logging do projeto. O sidecar de aceleração é um processo separado, acessado por meio de um transporte. O método de requisição carrega scope claims para autorização. Você deve tratar o limite do sidecar como um limite de confiança. Uma política de degradação definida como Permissive pode mascarar uma perda de capacidade relevante para a segurança. Use Strict quando a correção da saída for um controle. Trate o contexto de exceção, os eventos de job e as respostas do sidecar como dados que podem ser registrados em log, e sanitize-os conforme necessário.
Conformidade
Seção intitulada “Conformidade”Esta página não faz nenhuma afirmação normativa direta. Os contracts de observabilidade expõem o estado do engine e não implementam um protocolo padronizado cujas cláusulas o engine deva citar. As obrigações de telemetria segura e de sanitização de logs mencionadas acima derivam da política interna de logging do projeto, não de um padrão externo. Quando uma operação observada é, em si, padronizada — uma assinatura, um documento PDF/A —, sua conformidade fica documentada na página de assinatura ou de extração.
Veja também
Seção intitulada “Veja também”- Contracts: 41 interfaces públicas (SPI) — a visão geral da SPI e os níveis de estabilidade.
- Observabilidade — o módulo de estado de runtime que esses contracts expõem.
- Accelerator — o cliente do sidecar Spectrum por trás de
SpectrumInterface. - Exception — exceções que implementam
ContextAwareExceptionInterface. - Performance — os orçamentos contra os quais o trabalho observado é executado.