Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/visible/cruel/llms.txt

Use this file to discover all available pages before exploring further.

What are Scenarios?

Scenarios are time-based chaos patterns that simulate real-world incidents and failure conditions. Unlike static chaos injection, scenarios run for a specific duration and can model complex failure modes like network partitions, data center failovers, and traffic spikes.

Basic Usage

Define and play scenarios:
import { cruel } from 'cruel'

// Wrap your functions
const fetchData = cruel(async () => { /* ... */ })

// Define a scenario
cruel.scenario('network-outage', {
  chaos: { fail: 1 },  // 100% failure rate
  duration: 5000        // Lasts 5 seconds
})

// Play the scenario
await cruel.play('network-outage')

// Scenario stops automatically after 5 seconds
// Or stop manually:
cruel.stop()

Scenario API

cruel.scenario()

Define a reusable scenario:
cruel.scenario(name: string, config: {
  chaos?: ChaosOptions,
  duration?: number  // In milliseconds
})

cruel.play()

Start a scenario:
await cruel.play('scenario-name')
// Returns after scenario duration completes

// Or without await for background execution
cruel.play('scenario-name')  // Runs in background

cruel.stop()

Manually stop the active scenario:
cruel.stop()  // Disables chaos and clears active scenario

cruel.activeScenario()

Check which scenario is running:
const active = cruel.activeScenario()
if (active) {
  console.log(`Currently running: ${active}`)
} else {
  console.log('No active scenario')
}

Built-in Scenarios

Cruel includes 12 pre-configured scenarios for common failure modes:

networkPartition

Complete network failure:
await cruel.play('networkPartition')
// { fail: 1, duration: 5000 }
  • 100% failure rate - All requests fail
  • 5 second duration
  • Use case: Test network split-brain scenarios

highLatency

Severe latency spike:
await cruel.play('highLatency')
// { delay: [2000, 5000], duration: 10000 }
  • 2-5 second delays
  • 10 second duration
  • Use case: Test timeout handling and user experience degradation

degraded

Partial service degradation:
await cruel.play('degraded')
// { fail: 0.1, delay: [500, 1500], duration: 30000 }
  • 10% failure rate
  • 500-1500ms latency
  • 30 second duration
  • Use case: Test graceful degradation under load

outage

Major service outage:
await cruel.play('outage')
// { fail: 1, timeout: 0.5, duration: 60000 }
  • 100% failures and 50% timeouts
  • 60 second duration
  • Use case: Test disaster recovery procedures

recovery

Post-incident recovery phase:
await cruel.play('recovery')
// { fail: 0.3, delay: [100, 500], duration: 15000 }
  • 30% failure rate
  • 100-500ms latency
  • 15 second duration
  • Use case: Test system behavior during recovery

blackFriday

High traffic with intermittent issues:
await cruel.play('blackFriday')
// { delay: [1000, 3000], fail: 0.15, jitter: 1000, duration: 60000 }
  • 1-3 second base latency
  • 15% failure rate
  • 0-1 second jitter
  • 60 second duration
  • Use case: Test black friday / traffic spike scenarios

mobileNetwork

Unstable mobile connectivity:
await cruel.play('mobileNetwork')
// { delay: [500, 2000], fail: 0.2, timeout: 0.1, duration: 30000 }
  • 500-2000ms latency
  • 20% failures, 10% timeouts
  • 30 second duration
  • Use case: Test mobile app resilience

datacenterFailover

Data center switching:
await cruel.play('datacenterFailover')
// { fail: 0.5, delay: [200, 800], duration: 20000 }
  • 50% failure rate
  • 200-800ms latency
  • 20 second duration
  • Use case: Test multi-region failover logic

ddosAttack

DDoS-like overload:
await cruel.play('ddosAttack')
// { timeout: 0.4, delay: [2000, 10000], duration: 30000 }
  • 40% timeouts
  • 2-10 second delays
  • 30 second duration
  • Use case: Test rate limiting and backpressure

coldStart

Serverless cold start delays:
await cruel.play('coldStart')
// { delay: [3000, 8000], duration: 10000 }
  • 3-8 second delays
  • 10 second duration
  • Use case: Test serverless initialization latency

gcPause

Garbage collection pauses:
await cruel.play('gcPause')
// { delay: [100, 500], spike: [500, 2000], duration: 15000 }
  • 100-500ms base delay
  • 500-2000ms occasional spikes
  • 15 second duration
  • Use case: Test impact of GC pauses

connectionPool

Connection pool exhaustion:
await cruel.play('connectionPool')
// { fail: 0.3, timeout: 0.2, duration: 20000 }
  • 30% failures, 20% timeouts
  • 20 second duration
  • Use case: Test connection pool management

Creating Custom Scenarios

import { cruel } from 'cruel'

cruel.scenario('maintenance-window', {
  chaos: {
    fail: 0.5,
    delay: [1000, 2000]
  },
  duration: 30000  // 30 seconds
})

await cruel.play('maintenance-window')

Scenario Chains

Sequence scenarios to simulate complex incidents:
import { cruel } from 'cruel'

// Simulate incident lifecycle
async function simulateIncident() {
  console.log('Incident start: Network partition')
  await cruel.play('networkPartition')  // 5s total outage
  
  console.log('Partial recovery: Degraded service')
  await cruel.play('degraded')  // 30s degraded
  
  console.log('Recovering: Stabilizing')
  await cruel.play('recovery')  // 15s recovery
  
  console.log('Incident resolved')
}

await simulateIncident()

Using Scenarios in Tests

import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { cruel } from 'cruel'
import { fetchUserData } from './api'

describe('Resilience Tests', () => {
  beforeEach(() => {
    // Wrap functions before each test
    cruel(fetchUserData)
  })
  
  afterEach(() => {
    cruel.stop()
    cruel.reset()
  })
  
  it('handles network partition', async () => {
    await cruel.play('networkPartition')
    
    // Should use cached data during partition
    const result = await myApp.getUserData()
    expect(result).toBeTruthy()
    expect(result.source).toBe('cache')
  })
  
  it('recovers from degraded service', async () => {
    await cruel.play('degraded')
    
    // Should complete despite 10% failures
    const results = await Promise.allSettled(
      Array(100).fill(0).map(() => fetchUserData())
    )
    
    const successful = results.filter(r => r.status === 'fulfilled')
    expect(successful.length).toBeGreaterThan(80)
  })
})

Scenario Monitoring

Track scenario impact:
import { cruel } from 'cruel'

cruel.scenario('test-chaos', {
  chaos: { fail: 0.2, delay: [500, 1500] },
  duration: 30000
})

const before = cruel.stats()

await cruel.play('test-chaos')

const after = cruel.stats()

console.log('Scenario Impact:')
console.log(`Total calls: ${after.calls - before.calls}`)
console.log(`Failures: ${after.failures - before.failures}`)
console.log(`Avg latency: ${after.avg}ms`)
console.log(`p95 latency: ${after.p95}ms`)

Background Scenarios

Run scenarios without blocking:
import { cruel } from 'cruel'

// Start scenario in background (no await)
cruel.play('degraded')

// Continue with other operations
await runTests()
await collectMetrics()

// Scenario runs in parallel for 30 seconds
// Then stops automatically

Dynamic Scenarios

Create scenarios programmatically:
import { cruel } from 'cruel'

function createLoadScenario(load: 'low' | 'medium' | 'high') {
  const configs = {
    low: { fail: 0.05, delay: [100, 300] },
    medium: { fail: 0.15, delay: [300, 1000] },
    high: { fail: 0.3, delay: [1000, 3000] }
  }
  
  cruel.scenario(`load-${load}`, {
    chaos: configs[load],
    duration: 60000
  })
}

createLoadScenario('low')
createLoadScenario('medium')
createLoadScenario('high')

await cruel.play('load-high')

Best Practices

Test incrementally: Start with mild scenarios and progress to severe ones.
Document results: Record which scenarios your system can handle and which cause failures.
Automate: Run scenarios in CI/CD to catch resilience regressions.
Duration matters: Longer scenarios reveal issues that short bursts might miss.

Scenario Comparison

ScenarioFailure %Timeout %Max DelayDurationSeverity
degraded10%0%1.5s30sLow
mobileNetwork20%10%2s30sMedium
datacenterFailover50%0%0.8s20sMedium
ddosAttack0%40%10s30sHigh
outage100%50%-60sCritical
networkPartition100%0%-5sCritical

Next Steps

Chaos Injection

Learn about the underlying chaos mechanics

Presets

Use pre-configured chaos profiles

Statistics

Track chaos impact with detailed metrics

Testing Guide

Integrate scenarios into your test suite

Build docs developers (and LLMs) love