Getting Started
This guide will help you get started with Zenvark in your application.
Prerequisites
- Node.js: 22.x or higher
- Redis: 6.0 or higher
- Redis Streams support required (available in Redis 5.0+, but 6.0+ recommended)
Installation
Install Zenvark and its dependencies:
npm install zenvark ioredis
For Prometheus metrics support:
npm install @zenvark/prom prom-client
Quick Start
Here's a complete example showing how to set up and use a circuit breaker:
import { Redis } from "ioredis";
import { register } from "prom-client";
import {
CircuitBreaker,
ConsecutiveBreaker,
ConstantBackoff,
CircuitOpenError,
HealthCheckType,
CircuitRole,
CircuitState,
} from "zenvark";
import { PrometheusBreakerMetrics } from "@zenvark/prom";
const redis = new Redis("redis://localhost:6379");
const circuitBreaker = new CircuitBreaker({
id: "my-service-api", // Unique ID for this circuit breaker
redis,
breaker: new ConsecutiveBreaker({ threshold: 5 }), // Open after 5 consecutive failures
health: {
backoff: new ConstantBackoff({ delayMs: 5000 }), // Wait 5 seconds between health checks
async check(type: HealthCheckType, signal: AbortSignal) {
// Your health check logic
const response = await fetch("https://api.example.com/health", {
signal,
});
if (!response.ok) throw new Error("Health check failed");
},
idleProbeIntervalMs: 30_000, // Run first probe 30s after last call, then every 30s while idle
},
onError: (err: Error) => {
// Handle or log internal circuit breaker errors here to prevent unhandled exceptions.
console.error("Circuit breaker error:", err);
},
onRoleChange: (role: CircuitRole) => {
// Observe leader election role changes
console.log("Circuit role changed to", role);
},
onStateChange: (state: CircuitState) => {
// Observe state transitions across the cluster
console.log("Circuit state changed to", state);
},
metrics: new PrometheusBreakerMetrics({
register, // Prometheus registry instance
customLabels: { service: "my-api" }, // Add custom labels to your metrics
}),
});
// Start the circuit breaker and its internal coordination mechanisms
await circuitBreaker.start();
// Execute operations protected by the circuit breaker
try {
const result = await circuitBreaker.execute(async () => {
// Your potentially failing operation
return await fetch("https://api.example.com/data");
});
console.log("Success:", result);
} catch (err) {
// `instanceof` for CircuitOpenError works reliably across realms
if (err instanceof CircuitOpenError) {
// Circuit is currently open – skipping request
} else {
// Underlying operation failed
}
}
// Clean up resources when your application shuts down
await circuitBreaker.stop();
Basic Usage Pattern
1. Create and Configure
Create a circuit breaker instance with your desired configuration:
const circuitBreaker = new CircuitBreaker({
id: "my-service-api",
redis,
breaker: new ConsecutiveBreaker({ threshold: 5 }),
health: {
backoff: new ConstantBackoff({ delayMs: 5000 }),
async check(type: HealthCheckType, signal: AbortSignal) {
// Health check implementation
},
},
});
2. Start
Start the circuit breaker before using it:
await circuitBreaker.start();
3. Execute Protected Operations
Wrap your operations with the circuit breaker:
try {
const result = await circuitBreaker.execute(async () => {
return await callExternalService();
});
} catch (err) {
if (err instanceof CircuitOpenError) {
// Handle blocked requests
} else {
// Handle operation failures
}
}
4. Stop
Clean up when shutting down:
await circuitBreaker.stop();