All files method-fuse.ts

97.96% Statements 48/49
68.75% Branches 11/16
100% Functions 7/7
100% Lines 40/40

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 841x   1x                 1x   2x     2x     2x     2x     2x     2x   2x   2x 2x 2x 2x 2x     1x 3x 3x 3x     13x 13x 13x     1x 2x   28x 14x 1x 1x 1x       13x 1x     1x   1x 1x 1x       12x     12x 12x   12x     1x  
import { Logger } from '@jerryc/mini-logger';
 
export const logger = new Logger({ prefix: 'method-fuse' });
 
export interface MethodFuseOptions {
  name?: string;
  maxLoad?: number;
  breakingTime?: number;
  coolDownTime?: number;
}
 
export class MethodFuse {
  // 保险丝名称
  private name = 'unnamed';
 
  // 最大负荷量,单位:调用次数
  private maxLoad = 3;
 
  // 当前负荷量,单位:调用次数
  private curLoad = 0;
 
  // 熔断持续时间,单位 ms
  private breakingTime = 5000;
 
  // 熔断状态
  private breaked = false;
 
  // 自动冷却时间,单位 ms
  private coolDownTime = 1000;
 
  private resetTimer = null;
 
  constructor(Iparams: MethodFuseOptions = {}) {
    Eif (params.name) this.name = params.name;
    Eif (params.maxLoad) this.maxLoad = params.maxLoad;
    Eif (params.breakingTime) this.breakingTime = params.breakingTime;
    Iif (params.coolDownTime) this.coolDownTime = params.coolDownTime;
  }
 
  public reset() {
    this.breaked = false;
    this.curLoad = 0;
    logger.info(`${this.name}-保险丝重置`);
  }
 
  public resetAfter(ms) {
    if (this.resetTimer) clearTimeout(this.resetTimer);
    this.resetTimer = setTimeout(() => this.reset(), ms);
  }
 
  public proxy(originMethod: (...any) => Promise<any>) {
    const that = this;
 
    return async function (this: any, ...args) {
      if (that.breaked) {
        const message = `${that.name}-保险丝已熔断,请稍后重试`;
        logger.error(message);
        throw new Error(message);
      }
 
      // 已达最大重试次数
      if (that.curLoad >= that.maxLoad) {
        that.breaked = true;
 
        // 重置保险丝
        that.resetAfter(that.breakingTime);
 
        const message = `${that.name}-保险丝熔断,${that.breakingTime}ms 之后重铸`;
        logger.error(message);
        throw new Error(message);
      }
 
      // 自动冷却系统
      that.resetAfter(that.coolDownTime);
 
      // 允许当前请求通过保险丝,记录 +1
      that.curLoad = that.curLoad + 1;
      logger.info(`${that.name}-通过保险丝(${that.curLoad}/${that.maxLoad})`);
 
      return originMethod.apply(this, ...args);
    };
  }
}