Pular para o conteúdo

Chaos: arcabouço determinístico para cenários de resiliência

O módulo Chaos é um arcabouço compacto para testes de resiliência. Você registra cenários de injeção de falhas que implementam uma interface de método único, executa esses cenários e consolida um relatório estruturado de pass/fail. Ele permanece deliberadamente pequeno, com cinco classes, e pertence a suítes de resiliência e exercícios de chaos-day, não ao caminho de produção de documentos.

Estabilidade: experimental. Esta é uma superfície de ferramentas de teste e resiliência, não a interface de programação de aplicações (API) central do Portable Document Format (PDF). A interface de provedor de serviços (SPI) é pequena e tem formato estável, mas o escopo do módulo e os cenários incluídos evoluem. Não construa fluxo de controle de produção sobre este módulo.

Terminal window
composer require nextpdf/core:^3

Um teste de resiliência verifica se o motor se degrada corretamente quando uma dependência falha. O módulo Chaos dá estrutura a esse teste. ChaosScenarioInterface é o contrato do cenário: name() identifica o cenário, e simulate() retorna um ChaosOutcome. Cada cenário encapsula uma falha, como uma partição de rede ou uma rajada de respostas 5xx do backend de recuperação, e informa o que aconteceu.

ChaosScenarioRunner orquestra a execução. Você usa register() para registrar cenários, chama run() para executá-los sequencialmente na ordem de registro e, depois, lê o agregado com outcomes(), allPassed(), passCount() e failCount(). O executor nunca lança exceção por causa de uma falha de cenário: uma falha é um dado capturado em um ChaosOutcome, não uma exceção. Ele só lança exceção quando a própria infraestrutura está quebrada, como um registro de cenário inválido ou a impossibilidade de gravar o arquivo de relatório (ChaosReportWriteException). Um cenário que não consegue acessar o recurso que está testando expõe uma RetrievalUnavailableException. O módulo está marcado como @since 3.2.0.

ChaosOutcome armazena o resultado de cada cenário: status pass/fail, duração e a saída de toArray() para o relatório estruturado. Como um resultado registra a duração em tempo real (wall-clock), o perfil de reprodutibilidade do relatório é structural, não bitwise.

TipoMembros principaisFunção
ChaosScenarioInterfacename(): string, simulate(): ChaosOutcomeContrato do cenário (@since 3.2.0)
ChaosScenarioRunnerregister(), run(), outcomes(), allPassed(), passCount(), failCount()Orquestrador sequencial de cenários (@since 3.2.0)
ChaosOutcomedurationSeconds(), toArray()Resultado pass/fail por cenário (@since 3.2.0)
RetrievalUnavailableExceptionO recurso testado estava inacessível
ChaosReportWriteExceptionO arquivo de relatório não pôde ser gravado

Execute composer docs:generate-api-php -- --module=Chaos para gerar a tabela completa de PHPDoc.

Registre um cenário e, em seguida, execute a suíte.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Chaos\ChaosOutcome;
use NextPDF\Chaos\ChaosScenarioInterface;
use NextPDF\Chaos\ChaosScenarioRunner;
final class TimeoutScenario implements ChaosScenarioInterface
{
public function name(): string
{
return 'dependency-timeout';
}
public function simulate(): ChaosOutcome
{
// Inject the fault, observe the engine's degradation, return the verdict.
return new ChaosOutcome(/* name, passed, durationSeconds, details */);
}
}
$runner = new ChaosScenarioRunner();
$runner->register(new TimeoutScenario());
$runner->run();
echo $runner->allPassed() ? "Resilient.\n" : "{$runner->failCount()} scenario(s) failed.\n";

Execute o arcabouço a partir de um job de resiliência e retorne um código de saída diferente de zero para qualquer falha, sem permitir que uma falha de cenário escape como exceção.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Chaos\ChaosScenarioRunner;
use NextPDF\Chaos\Exception\ChaosReportWriteException;
use Psr\Log\LoggerInterface;
final readonly class ChaosJob
{
/** @param list<\NextPDF\Chaos\ChaosScenarioInterface> $scenarios */
public function __construct(
private array $scenarios,
private LoggerInterface $logger,
) {}
public function run(string $reportPath): int
{
$runner = new ChaosScenarioRunner();
foreach ($this->scenarios as $scenario) {
$runner->register($scenario);
}
$runner->run(); // never throws on scenario failure
try {
$runner->writeReport($reportPath);
} catch (ChaosReportWriteException $e) {
$this->logger->error('Chaos report could not be written.', ['error' => $e->getMessage()]);
return 2;
}
return $runner->allPassed() ? 0 : 1;
}
}
  • run() nunca lança exceção por um cenário ter falhado. Uma falha fica em ChaosOutcome. Se você envolver run() em um try/catch esperando falhas ali, você não as verá. Em vez disso, leia failCount() / allPassed().
  • O executor lança exceção apenas em falhas de infraestrutura: um registro inválido ou uma ChaosReportWriteException quando o caminho do relatório não pode ser gravado. Trate essas falhas separadamente dos resultados dos cenários.
  • Os cenários são executados sequencialmente na ordem de registro. Não há paralelismo. A ordem pode fazer diferença quando os cenários compartilham estado externo.
  • Este módulo é para testes de resiliência. Não importe o executor para o caminho de produção de documentos como mecanismo de controle.

O executor acrescenta sobrecarga desprezível. O comportamento do cenário determina o custo. Como os cenários injetam falhas e podem aguardar timeouts, uma execução de chaos pode ser lenta por concepção. O performance_budget aqui é o valor de referência do motor, não um limite para a duração do cenário. O perfil de reprodutibilidade é structural: o relatório registra durações em tempo real (wall-clock), portanto esses campos diferem entre execuções.

Os cenários injetam falhas e podem exercitar caminhos de falha em dependências. Execute o arcabouço apenas em um ambiente de teste ou de staging, com credenciais e endpoints restritos a esse ambiente. Nunca o execute contra sistemas de produção. O relatório pode conter detalhes de diagnóstico sobre modos de falha. Trate-o como interno e cumpra a obrigação de higienização de logs do projeto antes de compartilhá-lo. Consulte o modelo de ameaças do motor em /modules/core/security/.

Este módulo não faz nenhuma declaração normativa sobre a especificação do PDF. Ele fornece ferramentas de resiliência. Não implementa nenhum protocolo padronizado cujas cláusulas devam ser citadas. As suítes de oracle e golden descritas em /modules/core/conformance/ validam a conformidade do motor.