Ga naar inhoud

Chaos: deterministisch testharnas voor veerkrachtscenario's

De Chaos-module is een compact harnas voor veerkrachttests. Je registreert foutinjectiescenario’s die een interface met één methode implementeren, voert ze uit en verzamelt een gestructureerd pass/fail-rapport. De module blijft bewust klein met vijf klassen en hoort thuis in veerkrachtsuites en chaos-day-oefeningen, niet in het pad voor documentproductie.

Stabiliteit: experimenteel. Dit is een gereedschapsoppervlak voor tests en veerkracht, geen kern-API voor Portable Document Format (PDF). De service provider interface (SPI) is klein en heeft een stabiele vorm, maar de reikwijdte van de module en de meegeleverde scenario’s evolueren. Bouw er geen productie- besturingsstroom op.

Terminal window
composer require nextpdf/core:^3

Een veerkrachttest controleert of de engine correct degradeert wanneer een afhankelijkheid uitvalt. De Chaos-module geeft die test structuur. ChaosScenarioInterface is het scenariocontract: name() identificeert het scenario en simulate() retourneert een ChaosOutcome. Elk scenario kapselt één fout in, zoals een netwerkpartitie of een reeks 5xx-responses van de ophaal-backend, en rapporteert wat er is gebeurd.

ChaosScenarioRunner orkestreert de uitvoering. Je registreert scenario’s met register(), roept run() aan om ze sequentieel in registratievolgorde uit te voeren, en leest vervolgens het totaal met outcomes(), allPassed(), passCount() en failCount(). De runner gooit nooit een uitzondering bij een mislukking van een scenario: een mislukking is data die wordt vastgelegd in een ChaosOutcome, geen uitzondering. De runner gooit alleen een uitzondering wanneer de eigen infrastructuur defect is, zoals een ongeldige scenarioregistratie of wanneer het rapportbestand niet kan worden weggeschreven (ChaosReportWriteException). Een scenario dat de resource die het test niet kan bereiken, laat een RetrievalUnavailableException naar boven komen. De module is @since 3.2.0.

ChaosOutcome slaat het resultaat per scenario op: pass/fail-status, duur en toArray()-uitvoer voor het gestructureerde rapport. Omdat een uitkomst de duur in kloktijd registreert, is het reproduceerbaarheidsprofiel van het rapport structural, niet bitwise.

TypeBelangrijke ledenRol
ChaosScenarioInterfacename(): string, simulate(): ChaosOutcomeHet scenariocontract (@since 3.2.0)
ChaosScenarioRunnerregister(), run(), outcomes(), allPassed(), passCount(), failCount()Sequentiële scenario-orkestrator (@since 3.2.0)
ChaosOutcomedurationSeconds(), toArray()Pass/fail-resultaat per scenario (@since 3.2.0)
RetrievalUnavailableExceptionEen geteste resource was onbereikbaar
ChaosReportWriteExceptionHet rapportbestand kon niet worden weggeschreven

Voer composer docs:generate-api-php -- --module=Chaos uit om de volledige PHPDoc-tabel te genereren.

Registreer een scenario en voer vervolgens de suite uit.

<?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";

Stuur het harnas aan vanuit een veerkrachttaak en retourneer bij elke mislukking een exitcode ongelijk aan nul, zonder een scenariomislukking als uitzondering te laten ontsnappen.

<?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() gooit nooit een uitzondering omdat een scenario is mislukt. Een mislukking leeft in ChaosOutcome. Als je run() in een try/catch verpakt en verwacht daar mislukkingen te zien, zie je ze niet. Lees in plaats daarvan failCount() / allPassed().
  • De runner gooit alleen een uitzondering bij infrastructuurfouten: een onjuiste registratie, of een ChaosReportWriteException wanneer er niet naar het rapportpad kan worden geschreven. Behandel die fouten los van de scenarioresultaten.
  • Scenario’s worden sequentieel in registratievolgorde uitgevoerd. Er is geen parallellisme. De volgorde kan van belang zijn wanneer scenario’s externe status delen.
  • Deze module is bedoeld voor het testen van veerkracht. Importeer de runner niet als besturingsmechanisme in het pad voor documentproductie.

De runner voegt verwaarloosbare overhead toe. Het gedrag van het scenario bepaalt de kosten. Omdat scenario’s fouten injecteren en kunnen wachten op time-outs, kan een chaos-uitvoering bewust traag zijn. De performance_budget is hier de referentiewaarde van de engine, geen grens voor de duur van een scenario. Het reproduceerbaarheidsprofiel is structural: het rapport registreert duren in kloktijd, dus die velden verschillen tussen uitvoeringen.

Scenario’s injecteren fouten en kunnen foutpaden in afhankelijkheden aanspreken. Voer het harnas uitsluitend uit in een test- of stagingomgeving, met inloggegevens en eindpunten die tot die omgeving beperkt zijn. Voer het nooit uit tegen productiesystemen. Het rapport kan diagnostische details over foutmodi bevatten. Behandel het als intern en pas de log-scrubbingverplichting van het project toe voordat je het deelt. Zie het threat model van de engine in /modules/core/security/.

Deze module doet geen normatieve uitspraak over de PDF-specificatie. Het is gereedschap voor veerkracht. Het implementeert geen gestandaardiseerd protocol waarvan de clausules moeten worden geciteerd. De oracle- en golden-suites die in /modules/core/conformance/ worden beschreven, valideren de conformiteit van de engine.