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.

Basic Chaos Examples

Get started with chaos engineering using Cruel’s core functions. These examples demonstrate basic failure injection, delays, and reliability testing.

Wrapping Functions with Chaos

The simplest way to inject chaos is wrapping a function with cruel():
import { cruel } from 'cruel'

async function fetchData() {
  const response = await fetch('https://api.example.com/data')
  return response.json()
}

// Add 10% failure rate
const unreliableFetch = cruel(fetchData, { fail: 0.1 })

try {
  const data = await unreliableFetch()
  console.log('Success:', data)
} catch (error) {
  console.error('Failed:', error.message)
}

Adding Delays

1
Fixed Delay
2
Add a consistent delay to simulate slow responses:
3
const slowFetch = cruel(fetchData, { delay: 500 })

// Every call will wait 500ms before executing
const data = await slowFetch()
4
Variable Delay
5
Use a range to randomize delays:
6
const variableFetch = cruel(fetchData, { 
  delay: [100, 1000] // Random delay between 100-1000ms
})
7
Delay with Jitter
8
Add random jitter for more realistic network conditions:
9
const jitteryFetch = cruel(fetchData, {
  delay: 200,
  jitter: 100 // Adds 0-100ms of random jitter
})

Common Failure Patterns

Inject random failures:
import { cruel } from 'cruel'

const fn = async () => 'success'
const flaky = cruel.fail(fn, 0.2) // 20% failure rate

try {
  const result = await flaky()
} catch (error) {
  // CruelError: injected failure
  console.error(error)
}

Deterministic Testing with Seeds

Make chaos reproducible for testing:
import { cruel } from 'cruel'
import { describe, test, beforeEach } from 'bun:test'

beforeEach(() => {
  cruel.reset()
})

test('reproducible chaos', async () => {
  cruel.seed(12345) // Set deterministic seed

  const fn = async () => 'ok'
  const wrapped = cruel.fail(fn, 0.5)

  // Run 1
  const results1 = []
  for (let i = 0; i < 10; i++) {
    try {
      await wrapped()
      results1.push('success')
    } catch {
      results1.push('failure')
    }
  }

  // Reset with same seed
  cruel.seed(12345)

  // Run 2 - identical results
  const results2 = []
  for (let i = 0; i < 10; i++) {
    try {
      await wrapped()
      results2.push('success')
    } catch {
      results2.push('failure')
    }
  }

  expect(results1).toEqual(results2)
})

Tracking Statistics

Monitor chaos impact on your functions:
import { cruel } from 'cruel'

const fn = async () => 'ok'
const wrapped = cruel(fn, { fail: 0.1, delay: [50, 200] })

// Make some calls
for (let i = 0; i < 100; i++) {
  try {
    await wrapped()
  } catch {}
}

// Check statistics
const stats = cruel.stats()
console.log({
  calls: stats.calls,
  failures: stats.failures,
  timeouts: stats.timeouts,
  delays: stats.delays,
  avgLatency: stats.avg,
  p95: stats.p95,
  p99: stats.p99
})

// Reset for next test
cruel.resetStats()

Testing Complete Example

import { cruel } from 'cruel'
import { describe, test, beforeEach, expect } from 'bun:test'

beforeEach(() => {
  cruel.reset()
})

describe('API client with chaos', () => {
  async function fetchUser(id: string) {
    const response = await fetch(`https://api.example.com/users/${id}`)
    return response.json()
  }

  test('handles failures gracefully', async () => {
    const unreliableFetch = cruel(fetchUser, { fail: 1 })

    try {
      await unreliableFetch('123')
      expect(true).toBe(false) // Should not reach
    } catch (error) {
      expect(error.name).toBe('CruelError')
    }
  })

  test('retries on failure', async () => {
    let attempts = 0
    const fetchWithRetry = async (id: string) => {
      attempts++
      if (attempts < 3) throw new Error('fail')
      return { id, name: 'John' }
    }

    const resilient = cruel.retry(fetchWithRetry, {
      attempts: 3,
      delay: 10
    })

    const user = await resilient('123')
    expect(user.name).toBe('John')
    expect(attempts).toBe(3)
  })

  test('measures latency under chaos', async () => {
    const delayed = cruel(fetchUser, { delay: 100 })

    const start = Date.now()
    try {
      await delayed('123')
    } catch {}
    const elapsed = Date.now() - start

    expect(elapsed).toBeGreaterThanOrEqual(100)
  })
})

Utility Functions

Cruel provides helpful utilities for randomness and control flow:
// Random boolean based on probability
import { cruel } from 'cruel'

if (cruel.coin(0.3)) {
  console.log('30% chance - this happened!')
}

Next Steps

Build docs developers (and LLMs) love