Skip to content

Configuration

Options

CircuitBreakerPlugin accepts ICircuitBreakerPluginOptions:

OptionTypeDefaultDescription
failureThresholdnumber5Failures within windowMs that trip CLOSED → OPEN.
windowMsnumber10000Rolling window (ms) over which failures are counted in CLOSED.
openDurationMsnumber30000Time (ms) the breaker stays OPEN before probes are allowed.
halfOpenMaxCallsnumber1Max probe calls permitted while HALF_OPEN.
successThresholdnumber1Successful probes required to close (must be ≤ halfOpenMaxCalls).
probeTimeoutMsnumberopenDurationMsTime (ms) a permitted HALF_OPEN probe may stay unresolved before its slot is reclaimed (protects against crashed probes).
keyPrefixstring'cb:'Redis key prefix for circuit state.
clientstring'default'Named Redis client to use.
errorPolicy'fail-open' | 'fail-closed''fail-closed'Behaviour when the state store is unavailable.
errorFactory(key, snapshot) => ErrorCustom error thrown when the breaker rejects a call.

All numeric knobs are validated at bootstrap (integers ≥ 1; successThreshold <= halfOpenMaxCalls) — an invalid config throws InvalidCircuitBreakerConfigError instead of silently misbehaving.

Synchronous Setup

typescript
import { Module } from '@nestjs/common';
import { RedisModule } from '@nestjs-redisx/core';
import { CircuitBreakerPlugin } from '@nestjs-redisx/circuit-breaker';

@Module({
  imports: [
    RedisModule.forRoot({
      clients: {
        host: 'localhost',
        port: 6379,
      },
      plugins: [
        new CircuitBreakerPlugin({
          failureThreshold: 5, // trip after 5 failures...
          windowMs: 10000, // ...within a 10s rolling window
          openDurationMs: 30000, // stay OPEN for 30s before probing
          halfOpenMaxCalls: 1, // allow 1 probe while HALF_OPEN
          successThreshold: 1, // 1 successful probe closes the breaker
          probeTimeoutMs: 30000, // reclaim a probe slot if its outcome is never recorded
        }),
      ],
    }),
  ],
})
export class AppModule {}

Asynchronous Setup

Load option values from ConfigService with CircuitBreakerPlugin.registerAsync, kept outside the connection useFactory (standard NestJS pattern):

typescript
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { RedisModule } from '@nestjs-redisx/core';
import { CircuitBreakerPlugin } from '@nestjs-redisx/circuit-breaker';

@Module({
  imports: [
    RedisModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      // Plugins live OUTSIDE useFactory (standard NestJS pattern). Their own
      // options can still be loaded asynchronously via registerAsync.
      plugins: [
        CircuitBreakerPlugin.registerAsync({
          imports: [ConfigModule],
          inject: [ConfigService],
          useFactory: (config: ConfigService) => ({
            failureThreshold: config.get<number>('CB_FAILURE_THRESHOLD', 5),
            openDurationMs: config.get<number>('CB_OPEN_MS', 30000),
          }),
        }),
      ],
      useFactory: (config: ConfigService) => ({
        clients: {
          type: 'single',
          host: config.get<string>('REDIS_HOST', 'localhost'),
          port: config.get<number>('REDIS_PORT', 6379),
        },
      }),
    }),
  ],
})
export class AppModule {}

Error Policy

errorPolicy decides what happens when the state store itself (Redis) is unavailable — it does not affect what happens when the breaker is simply OPEN (that always rejects unless you provide a fallback).

  • fail-closed (default): throw CircuitBreakerStoreError.
  • fail-open: run the guarded call anyway, favouring availability.
typescript
import { Module } from '@nestjs/common';
import { RedisModule } from '@nestjs-redisx/core';
import { CircuitBreakerPlugin } from '@nestjs-redisx/circuit-breaker';

@Module({
  imports: [
    RedisModule.forRoot({
      clients: { host: 'localhost', port: 6379 },
      plugins: [
        new CircuitBreakerPlugin({
          // errorPolicy governs what happens when the STATE STORE (Redis) is
          // unavailable — not when the breaker itself is OPEN.
          //
          // 'fail-open'  -> run the guarded call anyway (favor availability)
          // 'fail-closed' (default) -> throw CircuitBreakerStoreError
          errorPolicy: 'fail-open',
        }),
      ],
    }),
  ],
})
export class AppModule {}

Per-call Overrides

Every knob can be overridden per method (via the decorator) or per call (via execute), e.g. @WithCircuitBreaker({ key: 'x', failureThreshold: 10 }). See the decorator and service pages.

Released under the MIT License.