【问题标题】:Typescript: How to pass property through this in decorator?打字稿:如何在装饰器中通过这个传递属性?
【发布时间】:2021-12-21 05:22:48
【问题描述】:

我有一个重试装饰器,我把所有的 http 调用都放在了依赖项上。

类似:

@retry(3)
callToGoogle(..)
@retry(2)
callToMicrosoft(..)

我需要一种方法来检测函数内部的重试尝试。 我没有将尝试作为参数添加到函数的选项,因为这些函数具有可选参数,并且我的代码中的不同位置使用不同数量的参数调用它们。

由于某种原因,当我将此代码源部署到生产环境时 - 函数 foo 中的值 retryAttempt 未定义。 奇怪的是,这在单元测试中有效——这意味着 retryAttempt 已填充。我不知道这是怎么回事。

本地测试是一个保存我的应用程序的 node.js 进程,而生产环境是 kubernetes,它在多个 pod 上运行这个进程。我看不出有什么重要的原因。请帮帮我!

代码:

function retrySyncMethod(
    times: number,
    target: any,
    originalMethod: any,
    args: any[]): any {
    for (var attempt = 1; attempt < times; attempt++) {
        const nextAttempt: number = attempt + 1;
        target.currAttempt = nextAttempt;
        var result = originalMethod.apply(target, args);
        return result;
    }
}

export function retry(attempts: number):
    (target: Object,
        propertyKey: string,
        descriptor: TypedPropertyDescriptor<any>) => void {
    return function (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>): TypedPropertyDescriptor<any> {
        var originalMethod = descriptor.value; 

        descriptor.value = function (...args: any[]): any {
            var that = this;

            try {
                return originalMethod.apply(that, args);   
            } catch (err) {
                return retrySyncMethod(attempts, that, originalMethod, args);
            }
        };
        return descriptor;
    };
}

@retry(3)
function foo(host: string, path: string, optionaParam?: null) {
    const retryAttempt: number = (<any>this).currAttempt;
    if (retryAttempt > 2) {
        host = "changing host"
    }
    console.log("Mock Executing http request and throwing an error to simulate the need of retry");
    throw Error("Got 500 - throwing error in order to retry");
}

【问题讨论】:

    标签: typescript typescript-decorator


    【解决方案1】:

    如果您将更改主机逻辑移到实际方法之外并让装饰器调用它会怎样?如下:

    function changeHostIfNecessary(args: any[], attempt: Number, host: string): any[] {
      if ( attempt > 3 ) {
          const [, ...rest] = args
          return [host, rest]
      }
      return args
    }
    
    function retry(attempts: number, fallbackHost: string){
      return function (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>): TypedPropertyDescriptor<any> {
          var originalMethod = descriptor.value; 
          descriptor.value = function (...args: any[]): any {
              var that = this;
              let currentAttempt = 1
              do {
                  try {
                      const modArgs = changeHostIfNecessary(args, currentAttempt, fallbackHost)
                      originalMethod.apply(that, modArgs);   
                  } catch (err) {
                      currentAttempt++
                  }
                  
              } while(currentAttempt <= attempts)    
              
          };
          return descriptor;
      };
    }
    
    
    class Google{
        @retry(5, "alternateHost")
        public call(host: string, path: string, optionaParam?: null){
          console.log(`Calling with host :${host}...`)
          throw Error("Simulating a runtime exception.....")
        }
    }
    
    const g = new Google()
    g.call('InitialHost','doc/xyz')
    

    【讨论】:

      猜你喜欢
      • 2020-06-12
      • 2017-10-10
      • 2020-09-14
      • 2022-12-31
      • 2022-11-09
      • 2015-06-28
      • 2016-04-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多