first commit
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
# `ChaosEngine`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
Probabilistic failure injector for chaos testing. Each call to `step(nodes, edges)` rolls four independent dice (crash / partition / message-drop / transport-fault) using the simulator's seeded RNG, applies the relevant mutation, and appends a `ChaosEvent` to the engine's event log. Used to push the mesh past the predefined-scenario surface and surface bugs that only appear under noisy real-world conditions.
|
||||
|
||||
## Features
|
||||
|
||||
- Four configurable per-step probabilities — set any to `0` (or omit) to disable that chaos type.
|
||||
- Crash and transport-fault both pick a random victim from the live `nodes` array; partition picks a random victim edge from the supplied edge list.
|
||||
- Message-drop is decoupled from a specific message — it fires based on the per-step probability so callers can pair drops with arbitrary downstream traffic.
|
||||
- Event log is per-engine and survives `step` calls so test assertions can read the full chaos history in one shot.
|
||||
- Pure RNG via the simulator means deterministic chaos under a fixed seed.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
ChaosEngine,
|
||||
NetworkSimulator,
|
||||
VirtualNode,
|
||||
} from "@suaveplan/network-plugin-simulation";
|
||||
|
||||
const sim = new NetworkSimulator({ seed: 1 });
|
||||
const nodes = [new VirtualNode({ id: "n1", tier: 0 }, sim)];
|
||||
const chaos = new ChaosEngine(sim, { crashProbability: 0.5 });
|
||||
const events = chaos.step(nodes, []);
|
||||
console.log(events);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
ChaosEngine,
|
||||
NetworkSimulator,
|
||||
VirtualNode,
|
||||
} from "@suaveplan/network-plugin-simulation";
|
||||
|
||||
const sim = new NetworkSimulator({ seed: 99 });
|
||||
const nodes = Array.from(
|
||||
{ length: 5 },
|
||||
(_, i) => new VirtualNode({ id: `n${i}`, tier: i === 0 ? 0 : 1 }, sim)
|
||||
);
|
||||
const edges = nodes
|
||||
.slice(1)
|
||||
.map((n) => ({ from: "n0", to: n.id }));
|
||||
|
||||
const chaos = new ChaosEngine(sim, {
|
||||
crashProbability: 0.05,
|
||||
partitionProbability: 0.02,
|
||||
messageDropProbability: 0.10,
|
||||
transportFaultProbability: 0.01,
|
||||
});
|
||||
|
||||
for (let tick = 0; tick < 100; tick += 1) {
|
||||
sim.advanceBy(1);
|
||||
chaos.step(nodes, edges);
|
||||
}
|
||||
console.log(chaos.eventLog().length);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `class ChaosEngine(simulator, config?)`
|
||||
- `update(config: ChaosConfig): void`.
|
||||
- `step(nodes, edges): ReadonlyArray<ChaosEvent>` — events emitted this step.
|
||||
- `eventLog(): ReadonlyArray<ChaosEvent>` — full log since construction.
|
||||
- `reset(): void` — clears the event log.
|
||||
- `interface ChaosConfig` — `{ crashProbability?, partitionProbability?, messageDropProbability?, transportFaultProbability? }`.
|
||||
- `interface ChaosEvent` — `{ atMs, type, target?, target2? }`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The engine never throws — chaos is intentionally noisy and the simulator should not abort because of an unlucky roll. Caller code that wants to refuse particular events should filter the event log post-hoc.
|
||||
- Crash skips victims that are already not-running; transport-fault does not, because a transport fault on a downed node is still a meaningful test event for downstream dispatchers.
|
||||
- `messageDropProbability` is not paired with a specific message because the engine does not know about message identities — pair it with a downstream layer that consults the event log for "should I drop the next outbound?" decisions.
|
||||
- The four probabilities are independent — every step can emit between zero and four events.
|
||||
Reference in New Issue
Block a user