DI Integration
The circuitBreakerFactoryResolverDiFactory function creates an ICircuitBreakerFactoryResolver whose underlying resolver is resolved from a DI container.
The returned proxy implements both ICircuitBreakerFactoryResolver and ICircuitBreakerFactory:
use(adapterName?)selects an adapter on the resolvedCircuitBreakerFactoryResolver.create(key, settings?)creates a circuit breaker through the resolver's default adapter.
The proxy is wired to the container during container.init(). Create it before calling init(); calling use() or create() before the container is initialized throws an error.
Initial configuration
Set up the memory and Redis circuit-breaker adapters, create the container, then register the CircuitBreakerFactoryResolver and wrap it with circuitBreakerFactoryResolverDiFactory:
1. Set up the memory circuit-breaker adapter
import { DatabaseCircuitBreakerAdapter } from "eridu-tech/circuit-breaker/database-circuit-breaker-adapter";
import { MemoryCircuitBreakerStorageAdapter } from "eridu-tech/circuit-breaker/memory-circuit-breaker-storage-adapter";
export const memoryCircuitBreakerAdapter = new DatabaseCircuitBreakerAdapter({
adapter: new MemoryCircuitBreakerStorageAdapter(),
});
2. Set up the Redis circuit-breaker adapter
import { RedisCircuitBreakerAdapter } from "eridu-tech/circuit-breaker/redis-circuit-breaker-adapter";
import { Redis } from "ioredis";
export const redisCircuitBreakerAdapter = new RedisCircuitBreakerAdapter({
database: new Redis("YOUR_REDIS_CONNECTION_STRING"),
});
3. Create the dependency injection container
import { Container } from "eridu-tech/di";
import { ExecutionContext } from "eridu-tech/execution-context";
import { AlsExecutionContextAdapter } from "eridu-tech/execution-context/als-execution-context-adapter";
export const executionContext = new ExecutionContext(
new AlsExecutionContextAdapter(),
);
export const container = new Container({ executionContext });
4. Register and initialize the circuit-breaker factory resolver
import { CircuitBreakerFactoryResolver } from "eridu-tech/circuit-breaker";
import { ProxyCircuitBreakerFactoryResolver } from "eridu-tech/circuit-breaker/di";
import { container } from "./container.js";
import { memoryCircuitBreakerAdapter } from "./memory-circuit-breaker-adapter.js";
import { redisCircuitBreakerAdapter } from "./redis-circuit-breaker-adapter.js";
import { SuperJsonSerde } from "eridu-tech/serde/super-json-serde";
type Adapters = "memory" | "redis";
const serde = new SuperJsonSerde();
const circuitBreakerFactoryResolver =
new CircuitBreakerFactoryResolver<Adapters>({
serde,
adapters: {
memory: memoryCircuitBreakerAdapter,
redis: redisCircuitBreakerAdapter,
},
defaultAdapter: "memory",
});
await circuitBreakerFactoryResolver.init();
container.registerValue({
token: CircuitBreakerFactoryResolver,
value: circuitBreakerFactoryResolver,
});
// Create the proxy before container.init()
export const circuitBreakerFactory =
new ProxyCircuitBreakerFactoryResolver<Adapters>({
container,
resolverToken: CircuitBreakerFactoryResolver,
});
await container.init();
Usage
1. Using the default adapter
import { circuitBreakerFactory } from "./circuit-breaker-factory-resolver-di-factory.js";
// Uses the adapter configured as the default (memory)
await circuitBreakerFactory.create("shared-resource").runOrFail(async () => {
// code to run
});
2. Specifying an adapter explicitly
import { circuitBreakerFactory } from "./circuit-breaker-factory-resolver-di-factory.js";
// Uses the Redis adapter
await circuitBreakerFactory
.use("redis")
.create("shared-resource")
.runOrFail(async () => {
// code to run
});
Using it with the middlewares
Because the proxy implements ICircuitBreakerFactoryResolver, it can be passed straight to the circuit-breaker middleware factories:
import { withCircuitBreakerFactory } from "eridu-tech/circuit-breaker/middlewares";
import { use } from "eridu-tech/middleware";
import { circuitBreakerFactory } from "./circuit-breaker-factory-resolver-di-factory.js";
const withCircuitBreaker = withCircuitBreakerFactory(circuitBreakerFactory);
const callExternalApi = async (endpoint: string): Promise<unknown> => {
const response = await fetch(`https://api.example.com/${endpoint}`);
return response.json();
};
const protectedCall = use(
callExternalApi,
withCircuitBreaker.use("redis")({
key: ([endpoint]) => `api:${endpoint}`,
}),
);
await protectedCall("users");
Further information
For further information refer to eridu-tech/circuit-breaker API docs.