This is a wrapper for implementaion of Circuit Breaker pattern(made by hystrixjs) adapted for NestJS framework
- Every protected method must return a Promise as a result (so async functions and methods are fine and this is very convenient with NestJS)
- We can protect only methods of instances that are within NestJS components (annotated with @Component). This constraint comes from NestJS itself, cause it gives enough control (and possibilities for augmentation) only over @Components.
- Points above imply that if some of the functionality inside of a @Controller instance needs to be protected with a Circuit Breaker - this functionality must be extracted in to service (@Component instance).
- Augment service that needs protection.
- Annotate methods that need protection inside of the service with @CuircuitBreakerProtected annotation
- Provide an optional configuration for the @CuircuitBreakerProtected annotation
- Start watching over circuit breaker events (they will be logged)
@Module({
modules: [CoreModule],
controllers: [
CandidatesController
],
components: [
CandidatesService
]
})
export class NewCandidatesModule {
}
@Module({
modules: [CoreModule],
controllers: [
CandidatesController
],
components: [
{
provide: CandidatesService,
useFactory: (logger: Logger, config: Config, api: ApiHelperService) => {
return addCircuitBreakerSupportTo(new CandidatesService(config, api), CandidatesService);
},
inject: [
Logger, Config, ApiHelperService
]
}
]
})
export class NewCandidatesModule {
}
@Component()
export class CandidatesService {
// ...
@CircuitBreakerProtected({fallbackTo: defaultFallback})
async searchResumesNode(body: any) {
return await request({
// required request options
});
}
// ...
}
// All settings are optional and their default values provided below
@CircuitBreakerProtected({
circuitBreakerSleepWindowInMilliseconds: 3000,
circuitBreakerErrorThresholdPercentage: 50,
circuitBreakerRequestVolumeThreshold: 10,
timeout: 10000,
statisticalWindowLength: 10000,
statisticalWindowNumberOfBuckets: 10,
percentileWindowLength: 10000,
percentileWindowNumberOfBuckets: 10,
requestVolumeRejectionThreshold: 0,
fallbackTo: undefined,
shouldErrorBeConsidered: undefined
})
export class CoreModule {
constructor(private logger: Logger,
private config: Config,
private sendgridService: SendgridService) {
const startObservingCircuitBreakerState = makeCircuitBreakerStateObserver(this.sendgridService, logger, config);
// Every 5 seconds (be default) Circuit Breaker will be polled and all opened ones (this is when back off is active)
//get logged along with health stats
startObservingCircuitBreakerState();
}
}
> "CandidatesService.searchResumesNode" circuit breaker is active.
> Health stats: {totalCount: 100, errorCount: 80, errorsPercentage: 80}