跳到內容

Chaos:確定性韌性情境測試框架

Chaos 模組是一個用於韌性測試的小型框架。你會註冊實作單一方法介面的故障注入情境、執行它們,並收集一份結構化的 pass/fail 報告。它刻意維持極簡——僅五個類別——用於韌性測試套件與混沌演練(chaos-day),而非文件產製路徑。

穩定度:實驗性。 這是一個測試暨韌性工具面, 並非核心 PDF API。其 SPI 規模小、形態穩定,但本模組的範圍與隨附情境仍在演進。請勿以它建構正式環境的控制流程 。

Terminal window
composer require nextpdf/core:^3

韌性測試關心的是:當某個相依項失效時,引擎是否會正確降級?Chaos 模組為這項測試提供結構。ChaosScenarioInterface 是情境要實作的契約:一個 name(),以及一個會回傳 ChaosOutcomesimulate()。一個情境會封裝單一故障(網路分割、一連串擷取後端的 5xx 回應),並回報實際發生的狀況。

ChaosScenarioRunner 是協調者。你會用 register() 註冊情境、呼叫 run() 按註冊順序循序執行它們,並讀回彙整結果:outcomes()allPassed()passCount()failCount()。此 runner 絕不會因為情境失敗就拋出例外——失敗會被擷取為 ChaosOutcome 裡的資料,而不是例外。它只會在自身基礎設施出問題時拋出例外:無效的情境註冊,或無法寫入報告檔(ChaosReportWriteException)。無法觸及其所測試資源的情境,會讓 RetrievalUnavailableException 浮出。本模組整體為 @since 3.2.0

ChaosOutcome 代表每個情境的結果:pass/fail、一段持續時間,以及供結構化報告使用的 toArray()。由於 outcome 會記錄牆鐘(wall-clock)持續時間,該報告的可重現性設定檔為 structural,而非 bitwise

型別主要成員角色
ChaosScenarioInterfacename(): stringsimulate(): ChaosOutcome情境契約(@since 3.2.0
ChaosScenarioRunnerregister()run()outcomes()allPassed()passCount()failCount()循序情境協調者(@since 3.2.0
ChaosOutcomedurationSeconds()toArray()每個情境的 pass/fail 結果(@since 3.2.0
RetrievalUnavailableException某個受測資源無法觸及
ChaosReportWriteException無法寫入報告檔

執行 composer docs:generate-api-php -- --module=Chaos 以取得完整的 PHPDoc 表格。

註冊一個情境並執行套件。

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

由韌性工作(resilience job)驅動此框架,並將任何失敗視為非零離開碼,同時不讓情境失敗以例外形式逸出。

<?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() 絕不會因為某個情境失敗而拋出例外。失敗會記錄在 ChaosOutcome 之中。如果你把 run() 包在 try/catch,期待在那裡接住失敗,你永遠不會看到那些失敗——請改為讀取 failCount() / allPassed()
  • 此 runner 只會因基礎設施故障而拋出例外:錯誤註冊,或報告路徑不可寫入時的 ChaosReportWriteException。請將這些與情境結果分開處理。
  • 情境會依註冊順序循序執行。沒有平行處理。如果多個情境共用外部狀態,順序可能會有影響。
  • 本模組用於韌性測試。請勿將此 runner 當作控制機制放進文件產製路徑。

此 runner 的額外負擔可忽略不計。成本取決於情境實際做了什麼。由於情境會注入故障並可能等待逾時,一次混沌執行依設計本就可能很慢。此處的 performance_budget 是引擎的參考數值,並非情境持續時間的上限。其可重現性設定檔為 structural:報告會記錄牆鐘持續時間,因此兩次執行在這些欄位上會有所不同。

情境會注入故障,並可能觸發相依項中的失敗路徑。請只在測試或預備(staging)環境中執行此框架,且其憑證與端點都限定於該環境——絕不可針對正式環境系統執行。報告可能包含失敗模式相關診斷細節。請將其視為內部資料,並在分享前套用本專案的日誌清理(log-scrubbing)要求。請參閱 /modules/core/security/ 中的引擎威脅模型。

本模組未對任何 PDF 規範提出規範性宣告。它是韌性工具,也未實作任何必須引用其條款的標準化協定。引擎符合性由 /modules/core/conformance/ 中所述的 oracle 與黃金套件(golden suites)驗證。