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
Add a consistent delay to simulate slow responses:
const slowFetch = cruel(fetchData, { delay: 500 })
// Every call will wait 500ms before executing
const data = await slowFetch()
Use a range to randomize delays:
const variableFetch = cruel(fetchData, {
delay: [100, 1000] // Random delay between 100-1000ms
})
Add random jitter for more realistic network conditions:
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)
}
Add latency to responses:const slow = cruel.slow(fetchData, 1000)
// Or use a range
const variableSlow = cruel.slow(fetchData, [500, 2000])
Make functions never resolve:const timeout = cruel.timeout(fetchData, 0.1) // 10% timeout rate
// This may never resolve
const data = await timeout()
Combine multiple failure modes:const flaky = cruel.flaky(fetchData, 0.2)
// Adds:
// - 10% failures (0.2 * 0.5)
// - 5% timeouts (0.2 * 0.25)
// - 100-1000ms delay
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