Chaos: harness deterministico per scenari di resilienza
In sintesi
Sezione intitolata “In sintesi”Il modulo Chaos è un harness leggero per i test di resilienza. Consente di registrare scenari di iniezione di guasti che implementano un’interfaccia a un solo metodo, eseguirli e raccogliere un report pass/fail strutturato. È volutamente minimale — cinque classi — ed è pensato per suite di resilienza ed esercizi di chaos-day, non per il flusso di produzione dei documenti.
Stabilità: sperimentale. Si tratta di una superficie per strumenti di test e resilienza, non un’API PDF di base. L’SPI è piccolo e stabile nella forma, ma l’ambito del modulo e gli scenari inclusi evolvono. Non basarvi sopra flussi di controllo di produzione.
Installazione
Sezione intitolata “Installazione”composer require nextpdf/core:^3Panoramica concettuale
Sezione intitolata “Panoramica concettuale”Un test di resilienza si chiede: quando una dipendenza fallisce, il motore degrada correttamente? Il modulo Chaos fornisce a quel test una struttura. ChaosScenarioInterface è il contratto che uno scenario implementa — un name() e un simulate() che restituisce un ChaosOutcome. Uno scenario incapsula un singolo guasto (una partizione di rete, una raffica di risposte 5xx dal backend di recupero) e riporta ciò che è accaduto.
ChaosScenarioRunner è l’orchestratore. Si registrano gli scenari con register(), si chiama run() per eseguirli in sequenza nell’ordine di registrazione e si consultano i dati aggregati: outcomes(), allPassed(), passCount(), failCount(). Il runner non solleva mai un’eccezione per il fallimento di uno scenario — un fallimento è un dato registrato in un ChaosOutcome, non un’eccezione. Solleva un’eccezione solo quando è compromessa la propria infrastruttura: una registrazione di scenario non valida o l’impossibilità di scrivere il file del report (ChaosReportWriteException). Uno scenario che non riesce a raggiungere la risorsa che sta testando fa emergere una RetrievalUnavailableException. L’intero modulo è @since 3.2.0.
ChaosOutcome è il risultato del singolo scenario: pass/fail, una durata e un toArray() per il report strutturato. Poiché un esito registra la durata in tempo reale, il profilo di riproducibilità del report è structural, non bitwise.
Superficie API
Sezione intitolata “Superficie API”| Tipo | Membri principali | Ruolo |
|---|---|---|
ChaosScenarioInterface | name(): string, simulate(): ChaosOutcome | Contratto dello scenario (@since 3.2.0) |
ChaosScenarioRunner | register(), run(), outcomes(), allPassed(), passCount(), failCount() | Orchestratore sequenziale di scenari (@since 3.2.0) |
ChaosOutcome | durationSeconds(), toArray() | Risultato pass/fail del singolo scenario (@since 3.2.0) |
RetrievalUnavailableException | — | La risorsa testata era irraggiungibile |
ChaosReportWriteException | — | Non è stato possibile scrivere il file del report |
Eseguire composer docs:generate-api-php -- --module=Chaos per ottenere la tabella PHPDoc completa.
Esempio di codice — Avvio rapido
Sezione intitolata “Esempio di codice — Avvio rapido”Registrare uno scenario ed eseguire la suite.
<?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";Esempio di codice — Produzione
Sezione intitolata “Esempio di codice — Produzione”Eseguire l’harness da un job di resilienza e trattare qualsiasi fallimento come un codice di uscita diverso da zero, senza lasciare che il fallimento di uno scenario emerga come eccezione.
<?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; }}Casi limite e insidie
Sezione intitolata “Casi limite e insidie”run()non solleva mai un’eccezione per il fallimento di uno scenario. Un fallimento è contenuto inChaosOutcome. Se si racchiuderun()in un try/catch aspettandosi di intercettare lì i fallimenti, non li si vedrà mai — leggere invecefailCount()/allPassed().- Il runner solleva un’eccezione solo per guasti dell’infrastruttura: una registrazione errata o una
ChaosReportWriteExceptionquando il percorso del report non è scrivibile. Gestire questi casi separatamente dai risultati degli scenari. - Gli scenari vengono eseguiti in sequenza nell’ordine di registrazione. Non c’è parallelismo. L’ordine può essere rilevante se gli scenari condividono uno stato esterno.
- Questo modulo è destinato ai test di resilienza. Non importare il runner nel flusso di produzione dei documenti come meccanismo di controllo.
Prestazioni
Sezione intitolata “Prestazioni”L’overhead del runner è trascurabile. Il costo dipende da ciò che fanno gli scenari. Poiché gli scenari iniettano guasti e possono attendere timeout, un’esecuzione di chaos può essere lenta per progettazione. Il performance_budget qui è il valore di riferimento del motore, non un limite alla durata degli scenari. Il profilo di riproducibilità è structural: il report registra le durate in tempo reale, quindi due esecuzioni differiscono in quei campi.
Note di sicurezza
Sezione intitolata “Note di sicurezza”Gli scenari iniettano guasti e possono sollecitare i percorsi di fallimento nelle dipendenze. Eseguire l’harness solo in un ambiente di test o di staging con credenziali ed endpoint circoscritti a quell’ambiente — mai contro sistemi di produzione. Il report può contenere dettagli diagnostici sulle modalità di guasto. Trattarlo come interno e applicare la sanitizzazione dei log prevista dal progetto prima di condividerlo. Consultare il modello di minaccia del motore in /modules/core/security/.
Conformità
Sezione intitolata “Conformità”Questo modulo non formula alcuna affermazione normativa sulla specifica PDF. È uno strumento di resilienza. Non implementa alcun protocollo standardizzato le cui clausole debbano essere citate. La conformità del motore è convalidata dall’oracolo e dalle suite golden descritte in /modules/core/conformance/.
Vedere anche
Sezione intitolata “Vedere anche”- Modulo Observability — la superficie dello stato runtime che uno scenario osserva.
- Modulo Accelerator — un obiettivo comune per gli scenari di fallimento delle dipendenze.
- Panoramica sulla conformità
- Modello di sicurezza del motore