import {logger, MSG_FMT} from '../../internal/log';
import {Providers} from '../../providers';
export interface Command<T> {
execute(...args: unknown[]): Promise<T>;
}
export interface CommandOptions {
name: string;
run<T>(...args: unknown[]): Promise<T>;
}
export interface CommandFactory {
group?: string;
build<T>(options: CommandOptions): Command<T>;
}
export function CircuitBreaker(options: CommandOptions, commandFactory?: CommandFactory) {
return function (target: Record<string, any>, propertyKey: string | symbol, descriptor: PropertyDescriptor): void {
const log = logger('@CircuitBreaker');
log.debug(MSG_FMT.annotatingMethod, target.constructor.name, propertyKey, 'LogTime', options);
const original = descriptor.value;
descriptor.value = function circuitBreaker(...args: unknown[]): unknown {
const factory = commandFactory ? commandFactory : Providers.provide<CommandFactory>('CommandFactory');
let result;
if (factory) {
options.run = <T>(): Promise<T> => {
let result;
try {
const applied = original.apply(this, args);
if (applied instanceof Promise) {
result = applied;
} else {
result = new Promise((res) => res(applied));
}
} catch (error) {
result = new Promise((res, rej) => rej(error));
}
return result;
};
const command = factory?.build(options);
result = command.execute(...args);
} else {
// result = original.apply(target, args);
throw new Error(`Decorator @CircuitBreaker used on method [${target.constructor.name}.${String(propertyKey)}()] without a command factory configured! Make sure to call setCommandFactory().`);
}
return result;
};
}
}
|