npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

stability-sim

v0.2.0

Published

A dependency-free discrete-event simulator for distributed system stability experiments

Readme

stability-sim

A typed, dependency-free discrete-event simulation library for distributed-system stability experiments. The simulator was extracted from stability-sim into a standalone library with a CDK-like API.

Each distributed system component is a class that can be instantiated with a set of properties. Components can be connected to other components, and failures can be added to the scenario to simulate different failure scenarios. Once a scenario is created, it can be run synchronously.

Install

Node.js 22.18 or newer is required.

npm install stability-sim

Usage

import { Client, Distribution, LoadBalancer, LoadBalancerStrategy, Queue, Retry, Scenario, Server, ServerCrash, Traffic } from 'stability-sim';

const scenario = new Scenario({
  name: 'Metastable Retry Storm',
  endTime: 60,
  metricsWindowSize: 1,
  seed: 42,
});

const client = scenario.add(new Client('client-1', {
  trafficPattern: Traffic.openLoop({ meanArrivalRate: 70 }),
  retryStrategy: Retry.fixedN({ maxRetries: 3 }),
  timeout: 1,
}));

const loadBalancer = scenario.add(new LoadBalancer('lb-1', {
  strategy: LoadBalancerStrategy.ROUND_ROBIN,
}));

const queueA = scenario.add(new Queue('queue-a', {
  maxCapacity: 10_000,
  maxConcurrency: 5,
}));

const queueB = scenario.add(new Queue('queue-b', {
  maxCapacity: 10_000,
  maxConcurrency: 5,
}));

const serverA = scenario.add(new Server('srv-1', {
  serviceTimeDistribution: Distribution.exponential({ mean: 0.1 }),
  concurrencyLimit: 5,
}));

const serverB = scenario.add(new Server('srv-2', {
  serviceTimeDistribution: Distribution.exponential({ mean: 0.1 }),
  concurrencyLimit: 5,
}));

client.sendsTo(loadBalancer);
loadBalancer.routesTo(queueA);
loadBalancer.routesTo(queueB);
queueA.sendsTo(serverA);
queueB.sendsTo(serverB);

scenario.addFailure(new ServerCrash(serverA, {
  triggerTime: 5,
  recoveryTime: 10,
}));

const result = scenario.run({ snapshotInterval: 1 });
console.log(result.finalSnapshot);

In this distributed system simulation, a client connects to a load balancer, which routes requests to servers, whose buffers are represented by queues. A failure scenario, namely a short single server outage, is injected from T=5 to T=10, causing an amplified retry storm from clients that keeps both branches overloaded after the server recovers.

The result object contains information about the simulation which can be probed further:

const allSnapshots = result.snapshots; // an array of MetricSnapshot objects
const finalSnapshot = result.finalSnapshot; // the final MetricSnapshot object, for convenience

If we inspect the final snapshot, we can see metrics including the number of client requests successfully fulfilled, the number that were retried, the final size of the queues, as well as latency percentiles for the client:

console.log(finalSnapshot);
/*
{
  simTime: 59.99985197301004,
  componentMetrics: {
    'client-1': {
      completedCount: 662,
      failedCount: 13948,
      retriedCount: 10631,
      timedOutCount: 13474,
      inFlightCount: 281,
      tokenBucketTokens: 0
    },
    'lb-1': {
      tpsForwarded: 14891,
      totalFailed: 0,
      failedDownstreamCount: 0,
      errorRate: 0
    },
    'queue-a': {
      queueDepth: 4245,
      totalEnqueued: 7446,
      totalDequeued: 3201,
      totalRejected: 0
    },
    'queue-b': {
      queueDepth: 4437,
      totalEnqueued: 7445,
      totalDequeued: 3008,
      totalRejected: 0
    },
    'srv-1': {
      activeCount: 5,
      utilization: 1,
      tpsProcessed: 2722,
      totalRejected: 474,
      crashed: 0,
      latencySpikeMultiplier: 1,
      cpuReductionPercent: 0,
      errorRate: 0
    },
    'srv-2': {
      activeCount: 5,
      utilization: 1,
      tpsProcessed: 3003,
      totalRejected: 0,
      crashed: 0,
      latencySpikeMultiplier: 1,
      cpuReductionPercent: 0,
      errorRate: 0
    }
  },
  latencyPercentiles: {
    p50: 29.621504949269067,
    p95: 33.26896852844208,
    p99: 34.40729320856889,
    p999: 34.9146943670209
  },
  completedCount: 662,
  failedCount: 13948
}
*/

The docs below provide further information about the available APIs and how to use the simulator. For more examples, see the examples directory.

Low-level JSON API

A simulation can also be created from a raw JSON object by calling Scenario.fromJSON().

import type { ScenarioJSON } from 'stability-sim';

const document = {
  schemaVersion: 1,
  name: 'Low-level example',
  seed: 42,
  endTime: 5,
  metricsWindowSize: 1,
  components: [
    {
      id: 'client',
      type: 'client',
      config: {
        trafficPattern: { type: 'burst', count: 10, atTime: 0 },
        retryStrategy: { type: 'none' },
        targetComponentId: 'server',
        timeout: 1,
      },
    },
    {
      id: 'server',
      type: 'server',
      config: {
        serviceTimeDistribution: {
          type: 'uniform',
          min: 0.02,
          max: 0.04,
        },
        concurrencyLimit: 10,
      },
    },
  ],
  connections: [
    { id: 'client-to-server', sourceId: 'client', targetId: 'server' },
  ],
  failureScenarios: [],
};

const scenario = Scenario.fromJSON(document); // also accepts a JSON string
const result = scenario.run();

To serialize a builder scenario:

const document = scenario.toJSON();
const json = scenario.toJSONString(2);

Validation

There are some ways that a simulation can be created incorrectly, especially if it's created directly from JSON. The API provides two validation levels to help catch these issues:

  • TypeScript rejects incompatible relationships, failure targets, and malformed component props at development time.
  • Runtime validation checks numerical ranges, required connections, unique IDs, references, connection cardinality, and JSON discriminants.

Validation happens automatically before synthesis or execution. It is also directly accessible:

const issues = scenario.validate(); // readonly ValidationIssue[]
scenario.assertValid();             // throws ScenarioValidationError

Every runtime issue includes a stable code, JSON-style path, and message:

{
  code: ValidationIssueCode.INVALID_TOPOLOGY,
  path: '$.components[0]',
  message: 'client requires exactly one downstream connection',
}

Simulation control

scenario.run() will run a full simulation. For stepping or metric access, create a simulation session:

const simulation = scenario.createSimulation();

simulation.step();
simulation.currentTime;
simulation.queueSize;
simulation.snapshot();

const result = simulation.run({
  snapshotInterval: 0.5,
  latencyWindow: 10,
  maxEvents: 1_000_000,
  onSnapshot(snapshot) {
    console.log(snapshot.simTime, snapshot.completedCount);
  },
});

const points = simulation.getTimeSeries('api-a', 'utilization'); // TimeSeriesPoint[]
simulation.reset();

API reference

Public values

| API | Description | | --- | --- | | Cache | Pass-through cache component with probabilistic or keyed TTL behavior. | | Client | Workload source component configured with traffic and retry policies. | | Component | Abstract base class shared by builder component objects. | | Database | Terminal database processor with read/write latency and a connection pool. | | LoadBalancer | Pass-through router supporting round-robin, random, and least-connections selection. | | Queue | Pass-through buffer with capacity, concurrency, shedding, and ordering controls. | | Server | Terminal request processor with service-time and concurrency controls. | | Throttle | Pass-through component that limits concurrency or request rate. | | Connection | Typed directed relationship returned by component relationship methods. | | Traffic | Immutable factories for open-loop, closed-loop, ramping, and burst traffic patterns. | | Retry | Immutable factories for none, fixed-count, token-bucket, and circuit-breaker retries. | | Distribution | Immutable distribution factories and the union type they produce. | | LoadDependentLatency | Immutable load-scaling factories and the union type they produce. | | ThrottleMode | Immutable throttle-mode factories and the union type they produce. | | CacheFlush | Failure object that clears a cache at a configured simulation time. | | CpuReduction | Failure object that temporarily reduces a server's available concurrency. | | Failure | Abstract base class shared by typed failure objects. | | LatencySpike | Failure object that temporarily multiplies server or database latency. | | NetworkPartition | Failure object that temporarily disables a Connection. | | RandomError | Failure object that temporarily injects errors into a server or load balancer. | | ServerCrash | Failure object that crashes and later recovers a server or database. | | Scenario | Builder, validator, serializer, and entry point for running a scenario. | | ScenarioValidationError | Error containing every structured issue found during scenario validation. | | Simulation | Stateful synchronous simulation session supporting run, step, metrics, and reset. |

Enums

| Enum | Description | | --- | --- | | CacheEvictionPolicy | FIFO or LRU cache eviction policy. | | ComponentType | Stable serialized type of a simulation component. | | DistributionType | Uniform, exponential, or log-normal distribution discriminant. | | EventKind | Arrival, departure, failure, recovery, or timeout event kind. | | FailureType | Stable serialized type of an injectable failure. | | LoadBalancerStrategy | Round-robin, random, or least-connections routing strategy. | | LoadDependentLatencyMode | Linear, polynomial, or exponential load-scaling mode. | | QueueOrdering | FIFO or LIFO queue ordering. | | RetryStrategyType | Stable discriminant for a retry strategy. | | SimulationStatus | Idle, running, paused, or completed execution status. | | ThrottleModeType | Disabled, concurrency, or RPS throttle-mode discriminant. | | TrafficPatternType | Stable discriminant for a traffic pattern. | | ValidationIssueCode | Stable category assigned to a validation diagnostic. |

Component and connection types

| Type | Description | | --- | --- | | AnyComponent | Union of every high-level component object. | | CacheProps | Constructor properties for Cache, excluding its object-referenced downstream target. | | ClientProps | Constructor properties for Client, excluding its object-referenced target. | | ConnectableComponent | Union of component objects allowed as connection sources. | | DatabaseProps | Constructor properties for Database. | | LoadBalancerProps | Constructor properties for LoadBalancer. | | QueueProps | Constructor properties for Queue. | | ServerProps | Constructor properties for Server. | | TargetComponent | Union of component objects allowed as connection targets. | | TerminalComponent | Union of terminal Server and Database objects. | | ThrottleProps | Constructor properties for Throttle. | | ConnectionOptions | Optional relationship settings, currently the serialized connection ID. |

Factory result and property types

| Type | Description | | --- | --- | | OpenLoopTraffic | Traffic value produced by Traffic.openLoop(). | | OpenLoopTrafficProps | Properties accepted by Traffic.openLoop(). | | ClosedLoopTraffic | Traffic value produced by Traffic.closedLoop(). | | ClosedLoopTrafficProps | Properties accepted by Traffic.closedLoop(). | | RampingTraffic | Traffic value produced by Traffic.ramping(). | | RampingTrafficProps | Properties accepted by Traffic.ramping(). | | BurstTraffic | Traffic value produced by Traffic.burst(). | | BurstTrafficProps | Properties accepted by Traffic.burst(). | | NoRetry | Retry value produced by Retry.none(). | | FixedNRetry | Retry value produced by Retry.fixedN(). | | FixedNRetryProps | Properties accepted by Retry.fixedN(). | | TokenBucketRetry | Retry value produced by Retry.tokenBucket(). | | TokenBucketRetryProps | Properties accepted by Retry.tokenBucket(). | | CircuitBreakerRetry | Retry value produced by Retry.circuitBreaker(). | | CircuitBreakerRetryProps | Properties accepted by Retry.circuitBreaker(). | | UniformDistribution | Distribution value produced by Distribution.uniform(). | | UniformDistributionProps | Properties accepted by Distribution.uniform(). | | ExponentialDistribution | Distribution value produced by Distribution.exponential(). | | ExponentialDistributionProps | Properties accepted by Distribution.exponential(). | | LogNormalDistribution | Distribution value produced by Distribution.logNormal(). | | LogNormalDistributionProps | Properties accepted by Distribution.logNormal(). | | LinearLoadDependentLatency | Scaling value produced by LoadDependentLatency.linear(). | | LinearLoadDependentLatencyProps | Properties accepted by LoadDependentLatency.linear(). | | PolynomialLoadDependentLatency | Scaling value produced by LoadDependentLatency.polynomial(). | | PolynomialLoadDependentLatencyProps | Properties accepted by LoadDependentLatency.polynomial(). | | ExponentialLoadDependentLatency | Scaling value produced by LoadDependentLatency.exponential(). | | ExponentialLoadDependentLatencyProps | Properties accepted by LoadDependentLatency.exponential(). | | DisabledThrottleMode | Throttle value produced by ThrottleMode.disabled(). | | ConcurrencyThrottleMode | Throttle value produced by ThrottleMode.concurrency(). | | ConcurrencyThrottleModeProps | Properties accepted by ThrottleMode.concurrency(). | | RpsThrottleMode | Throttle value produced by ThrottleMode.rps(). | | RpsThrottleModeProps | Properties accepted by ThrottleMode.rps(). |

Failure types

| Type | Description | | --- | --- | | AnyFailure | Union of every high-level failure object. | | CacheFlushProps | Timing properties accepted by CacheFlush. | | CpuReductionProps | Timing and reduction properties accepted by CpuReduction. | | LatencySpikeProps | Timing and multiplier properties accepted by LatencySpike. | | NetworkPartitionProps | Timing properties accepted by NetworkPartition. | | RandomErrorProps | Timing and error-rate properties accepted by RandomError. | | ServerCrashProps | Crash and recovery timing properties accepted by ServerCrash. | | FailureScenario | Low-level discriminated union used to serialize failure scenarios by ID. |

Scenario, simulation, and validation types

| Type | Description | | --- | --- | | ScenarioOptions | Name, seed, duration, and metrics-window settings for Scenario. | | ValidationIssue | Structured validation diagnostic containing a code, path, and message. | | RunOptions | Snapshot, latency-window, event-limit, and callback options for a run. | | SimulationResult | Final status, counts, timing, snapshots, and metrics returned by a run. | | SnapshotOptions | Options controlling an on-demand metrics snapshot. |

Configuration, JSON, and metric types

| Type | Description | | --- | --- | | CacheConfig | Canonical low-level cache configuration including its downstream component ID. | | ClientConfig | Canonical low-level client configuration including its target component ID. | | DatabaseConfig | Canonical database latency, pool, and load-scaling configuration. | | Distribution | Discriminated union of uniform, exponential, and log-normal distributions. | | LoadBalancerConfig | Canonical load-balancer strategy configuration. | | LoadDependentLatency | Discriminated union of linear, polynomial, and exponential load scaling. | | QueueConfig | Canonical queue capacity, concurrency, shedding, and ordering configuration. | | RetryStrategy | Discriminated union of supported retry strategies. | | ServerConfig | Canonical server service-time, concurrency, and load-scaling configuration. | | ThrottleConfig | Canonical throttle configuration containing a ThrottleMode. | | ThrottleMode | Discriminated union of disabled, concurrency, and RPS throttle modes. | | TrafficPattern | Discriminated union of supported client traffic patterns. | | ComponentJSON | Low-level union of ID-based serialized component entries. | | SavedScenarioJSON | Existing application save-document shape accepted by Scenario.fromJSON(). | | ScenarioJSON | Canonical ID-based scenario document emitted by Scenario.toJSON(). | | LatencyPercentiles | P50, P95, P99, and P99.9 latency values. | | MetricSnapshot | Aggregate and per-component metrics captured at one simulation time. | | TimeSeriesPoint | One time/value pair returned from a metric series. |

Runnable TypeScript examples

Build the library once, then run any example directly with Node.js:

npm run build

node examples/metastable-retry.ts
node examples/gc-death-spiral.ts
node examples/connection-pool-exhaustion.ts
node examples/cache-stampede.ts
node examples/cache-flush.ts
node examples/timeout-cascade.ts
node examples/lb-sinkholing.ts
node examples/goodput-collapse.ts
node examples/from-json.ts

Development

The library has no dependencies. TypeScript, tsx, and Node types are development-only.

npm run typecheck
npm test
npm pack --dry-run

The build emits ESM JavaScript, source maps, and .d.ts declarations under dist/. Advanced low-level engine classes are available from stability-sim/engine.