Chaos : harnais déterministe pour scénarios de résilience
Le module Chaos est un harnais léger pour les tests de résilience. Tu enregistres des scénarios d’injection de fautes qui implémentent une interface à une seule méthode, tu les exécutes et tu collectes un rapport pass/fail structuré. Il est délibérément minimal — cinq classes — et destiné aux suites de résilience et aux exercices de chaos-day, pas au chemin de production des documents.
Stabilité : expérimentale. Il s’agit d’une surface d’outillage de test et de résilience, pas d’une API PDF du core. Le SPI est réduit et stable dans sa forme, mais la portée du module et les scénarios fournis évoluent. Ne construis pas de flux de contrôle de production sur cette base.
Installation
Section intitulée « Installation »composer require nextpdf/core:^3Vue d’ensemble conceptuelle
Section intitulée « Vue d’ensemble conceptuelle »Un test de résilience pose la question : quand une dépendance tombe en panne, le moteur se dégrade-t-il correctement ? Le module Chaos structure ce test. ChaosScenarioInterface est le contrat qu’un scénario implémente — un name() et un simulate() qui retourne un ChaosOutcome. Un scénario encapsule une faute (une partition réseau, une rafale de réponses 5xx du backend de récupération) et rapporte ce qui s’est passé.
ChaosScenarioRunner est l’orchestrateur. Tu enregistres des scénarios avec register(), tu appelles run() pour les exécuter séquentiellement dans l’ordre d’enregistrement, puis tu consultes l’agrégat : outcomes(), allPassed(), passCount(), failCount(). Le runner ne lève jamais d’exception sur un échec de scénario — un échec est une donnée capturée dans un ChaosOutcome, pas une exception. Il ne lève une exception que lorsque sa propre infrastructure est défaillante : un enregistrement de scénario invalide ou l’impossibilité d’écrire le fichier de rapport (ChaosReportWriteException). Un scénario qui ne peut pas atteindre la ressource qu’il teste remonte une RetrievalUnavailableException. L’ensemble du module est @since 3.2.0.
ChaosOutcome est le résultat par scénario : pass/fail, une durée et un toArray() pour le rapport structuré. Comme un outcome enregistre la durée d’horloge murale, le profil de reproductibilité du rapport est structural, pas bitwise.
Surface de l’API
Section intitulée « Surface de l’API »| Type | Membres clés | Rôle |
|---|---|---|
ChaosScenarioInterface | name(): string, simulate(): ChaosOutcome | Le contrat de scénario (@since 3.2.0) |
ChaosScenarioRunner | register(), run(), outcomes(), allPassed(), passCount(), failCount() | Orchestrateur séquentiel de scénarios (@since 3.2.0) |
ChaosOutcome | durationSeconds(), toArray() | Résultat pass/fail par scénario (@since 3.2.0) |
RetrievalUnavailableException | — | Une ressource testée était inaccessible |
ChaosReportWriteException | — | Le fichier de rapport n’a pas pu être écrit |
Exécute composer docs:generate-api-php -- --module=Chaos pour obtenir la table PHPDoc complète.
Exemple de code — Démarrage rapide
Section intitulée « Exemple de code — Démarrage rapide »Enregistre un scénario, puis exécute 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";Exemple de code — Production
Section intitulée « Exemple de code — Production »Pilote le harnais depuis un job de résilience et traite tout échec comme un code de sortie non nul, sans laisser un échec de scénario s’échapper sous forme d’exception.
<?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; }}Cas limites & pièges
Section intitulée « Cas limites & pièges »run()ne lève jamais d’exception parce qu’un scénario a échoué. Un échec vit dansChaosOutcome. Si tu enveloppesrun()dans un try/catch en t’attendant à y intercepter les échecs, tu ne les verras jamais — lis plutôtfailCount()/allPassed().- Le runner ne lève une exception que sur des défaillances d’infrastructure : un enregistrement invalide ou une
ChaosReportWriteExceptionquand le chemin du rapport n’est pas accessible en écriture. Traite-les distinctement des résultats de scénarios. - Les scénarios s’exécutent séquentiellement dans l’ordre d’enregistrement. Il n’y a aucun parallélisme. L’ordre peut avoir son importance si les scénarios partagent un état externe.
- Ce module sert aux tests de résilience. N’importe pas le runner dans le chemin de production de documents comme mécanisme de contrôle.
Performance
Section intitulée « Performance »La surcharge du runner est négligeable ; le coût vient de ce que font les scénarios. Comme les scénarios injectent des fautes et peuvent attendre l’expiration de timeouts, une exécution de chaos peut être lente par conception. Ici, le performance_budget correspond au chiffre de référence du moteur, pas à une borne sur la durée des scénarios. Le profil de reproductibilité est structural : le rapport enregistre des durées d’horloge murale, donc deux exécutions diffèrent sur ces champs.
Notes de sécurité
Section intitulée « Notes de sécurité »Les scénarios injectent des fautes et peuvent exercer les chemins d’échec des dépendances. N’exécute le harnais que dans un environnement de test ou de pré-production, avec des identifiants et des points de terminaison limités à cet environnement — jamais contre des systèmes de production. Le rapport peut contenir des détails de diagnostic sur les modes d’échec. Traite-le comme interne et respecte l’obligation de nettoyage des journaux du projet avant de le partager. Consulte le modèle de menace du moteur dans /modules/core/security/.
Conformité
Section intitulée « Conformité »Ce module n’affirme aucune revendication normative relative à la spécification PDF. C’est de l’outillage de résilience. Il n’implémente aucun protocole standardisé dont les clauses devraient être citées. La conformité du moteur est validée par l’oracle et les suites golden décrits dans /modules/core/conformance/.
Voir aussi
Section intitulée « Voir aussi »- Module Observability — la surface d’état d’exécution qu’un scénario observe.
- Module Accelerator — une cible courante pour les scénarios de défaillance de dépendances.
- Vue d’ensemble de la conformité
- Modèle de sécurité du moteur