ข้ามไปยังเนื้อหา

Chaos: เฟรมเวิร์กทดสอบความทนทานแบบกำหนดผลได้แน่นอน

โมดูล Chaos เป็นเฟรมเวิร์กขนาดกะทัดรัดสำหรับการทดสอบความทนทาน ผู้ใช้ลงทะเบียนสถานการณ์การฉีดข้อผิดพลาดที่ใช้อินเทอร์เฟซแบบเมธอดเดียว รันสถานการณ์เหล่านั้น แล้วรวบรวมรายงาน pass/fail ที่มีโครงสร้าง โมดูลนี้ตั้งใจออกแบบให้มีขนาดเล็กเพียงห้าคลาส และเหมาะกับชุดทดสอบความทนทานและการฝึกซ้อม chaos-day ไม่ใช่เส้นทางการผลิตเอกสาร

ความเสถียร: experimental นี่คือพื้นผิวเครื่องมือสำหรับทดสอบและตรวจสอบความทนทาน ไม่ใช่ application programming interface หลักของ Portable Document Format (PDF) (API) service provider interface (SPI) มีขนาดเล็กและมีรูปแบบที่เสถียร แต่ขอบเขตของโมดูลและสถานการณ์ที่มาพร้อมกันยังพัฒนาอย่างต่อเนื่อง อย่าสร้าง production control flow บนโมดูลนี้

Terminal window
composer require nextpdf/core:^3

การทดสอบความทนทานใช้ตรวจสอบว่าเอนจินลดระดับการทำงานได้ถูกต้องหรือไม่เมื่อ dependency ล้มเหลว โมดูล Chaos ให้โครงสร้างแก่การทดสอบลักษณะนี้ ChaosScenarioInterface คือสัญญาของสถานการณ์: name() ใช้ระบุสถานการณ์ และ simulate() คืนค่าเป็น ChaosOutcome แต่ละสถานการณ์ห่อหุ้มข้อผิดพลาดหนึ่งรายการ เช่น network partition หรือการตอบสนอง 5xx จำนวนมากจาก retrieval-backend ในช่วงเวลาสั้น ๆ แล้วรายงานสิ่งที่เกิดขึ้น

ChaosScenarioRunner ทำหน้าที่ประสานการรัน ผู้ใช้ register() สถานการณ์ เรียก run() เพื่อรันสถานการณ์เหล่านั้นทีละรายการตามลำดับการลงทะเบียน จากนั้นอ่านผลรวมด้วย outcomes(), allPassed(), passCount() และ failCount() runner จะไม่โยน exception เมื่อสถานการณ์ ล้มเหลว: ความล้มเหลวเป็นข้อมูลที่บันทึกไว้ใน ChaosOutcome ไม่ใช่ exception runner จะโยน exception เฉพาะเมื่อโครงสร้างพื้นฐานของตัวเองเสียหายเท่านั้น เช่น ลงทะเบียนสถานการณ์ไม่ถูกต้อง หรือเขียนไฟล์รายงานไม่ได้ (ChaosReportWriteException) สถานการณ์ที่เข้าถึงทรัพยากรที่กำลังทดสอบไม่ได้จะแสดง RetrievalUnavailableException โมดูลทั้งหมดมีเครื่องหมาย @since 3.2.0 กำกับอยู่

ChaosOutcome เก็บผลลัพธ์ของแต่ละสถานการณ์: สถานะ pass/fail ระยะเวลา และเอาต์พุตจาก toArray() สำหรับรายงานที่มีโครงสร้าง เนื่องจาก outcome บันทึกระยะเวลาตามนาฬิกาจริง โปรไฟล์ความสามารถในการทำซ้ำของรายงานจึงเป็นแบบ structural ไม่ใช่ bitwise

ชนิดสมาชิกหลักบทบาท
ChaosScenarioInterfacename(): string, simulate(): 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";

ขับเคลื่อนเฟรมเวิร์กจากงานตรวจสอบความทนทาน และคืนค่า exit code ที่ไม่ใช่ศูนย์เมื่อเกิดความล้มเหลวใด ๆ โดยไม่ปล่อยให้ความล้มเหลวของสถานการณ์หลุดออกมาเป็น 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;
}
}
  • run() จะไม่โยน exception เพียงเพราะสถานการณ์ ล้มเหลว ความล้มเหลวอยู่ใน ChaosOutcome หากห่อ run() ไว้ใน try/catch โดยคาดว่าจะพบความล้มเหลวที่นั่น จะไม่เห็นความล้มเหลวเหล่านั้น ให้อ่าน failCount() / allPassed() แทน
  • runner จะโยน exception เฉพาะเมื่อเกิดข้อผิดพลาดของโครงสร้างพื้นฐานเท่านั้น: การลงทะเบียนไม่ถูกต้อง หรือ ChaosReportWriteException เมื่อเส้นทางของรายงานเขียนไม่ได้ จัดการข้อผิดพลาดเหล่านั้นแยกจากผลลัพธ์ของสถานการณ์
  • สถานการณ์จะรันทีละรายการตามลำดับการลงทะเบียน ไม่มีการทำงานแบบขนาน ลำดับอาจมีผลเมื่อสถานการณ์ใช้สถานะภายนอกร่วมกัน
  • โมดูลนี้มีไว้สำหรับการทดสอบความทนทาน อย่านำ runner เข้าสู่เส้นทางการผลิตเอกสารเพื่อใช้เป็นกลไกควบคุม

runner เพิ่มภาระงานเพียงเล็กน้อยจนแทบไม่มีนัยสำคัญ พฤติกรรมของสถานการณ์เป็นตัวกำหนดต้นทุน เนื่องจากสถานการณ์ฉีดข้อผิดพลาดและอาจต้องรอ timeout การรัน chaos จึงอาจช้าได้โดยการออกแบบ performance_budget ในที่นี้คือตัวเลขอ้างอิงของเอนจิน ไม่ใช่ขอบเขตระยะเวลาของสถานการณ์ โปรไฟล์ความสามารถในการทำซ้ำเป็นแบบ structural: รายงานบันทึกระยะเวลาตามนาฬิกาจริง ดังนั้นฟิลด์เหล่านั้นจึงแตกต่างกันในแต่ละการรัน

สถานการณ์จะฉีดข้อผิดพลาดและอาจกระตุ้นเส้นทางความล้มเหลวใน dependency ให้รันเฟรมเวิร์กในสภาพแวดล้อมทดสอบหรือ staging เท่านั้น โดยจำกัดขอบเขตของ credential และ endpoint ให้อยู่ในสภาพแวดล้อมนั้น อย่ารันกับระบบ production โดยเด็ดขาด รายงานอาจมีรายละเอียดเชิงวินิจฉัยเกี่ยวกับโหมดความล้มเหลว ให้ถือว่ารายงานเป็นข้อมูลภายใน และปฏิบัติตามข้อกำหนดการล้างข้อมูลบันทึกของโครงการก่อนแบ่งปัน ดู threat model ของเอนจินได้ที่ /modules/core/security/ ในที่เก็บนี้

โมดูลนี้ไม่ได้กล่าวอ้างเชิงบรรทัดฐานใด ๆ ต่อข้อกำหนด PDF โมดูลนี้เป็นเครื่องมือสำหรับตรวจสอบความทนทาน และไม่ได้นำโปรโตคอลมาตรฐานใดที่ต้องอ้างอิงข้อกำหนดมาใช้งาน oracle และ golden suite ที่อธิบายไว้ใน /modules/core/conformance/ เป็นตัวตรวจสอบความสอดคล้องของเอนจิน