#typescript #typescript-decorator
Вопрос:
У меня есть декоратор повторных попыток, который я помещаю поверх всех своих http-вызовов для зависимости.
Что-то вроде:
@retry(3) callToGoogle(..)
@retry(2) callToMicrosoft(..)
Мне нужен способ определить, какая попытка повторения выполняется внутри функций. У меня нет возможности добавить попытку в качестве параметра в функцию, потому что эти функции имеют необязательные параметры, и в разных местах моего кода они вызываются с разным количеством параметров.
По какой — то причине, когда я развертываю этот исходный код в рабочей среде, значение retryAttempt
в функции foo
не определено. Странно, но это работает в модульном тесте — это означает retryAttempt
, что он заполнен. Я понятия не имею, что это не работает.
Локальный тест-это node.js процесс, в котором находится мое приложение, и среда prod-это kubernetes, которая запускает этот процесс в нескольких блоках. Я не вижу причины, по которой это имело бы значение. Пожалуйста, помогите мне!
Код:
function retrySyncMethod( times: number, target: any, originalMethod: any, args: any[]): any { for (var attempt = 1; attempt lt; 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: TypedPropertyDescriptorlt;anygt;) =gt; void { return function (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptorlt;anygt;): TypedPropertyDescriptorlt;anygt; { 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 = (lt;anygt;this).currAttempt; if (retryAttempt gt; 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"); }
Ответ №1:
Как насчет того, чтобы перенести логику изменения хоста за пределы вашего фактического метода и позволить декоратору вызвать его? Как показано ниже:
function changeHostIfNecessary(args: any[], attempt: Number, host: string): any[] { if ( attempt gt; 3 ) { const [, ...rest] = args return [host, rest] } return args } function retry(attempts: number, fallbackHost: string){ return function (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptorlt;anygt;): TypedPropertyDescriptorlt;anygt; { 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 lt;= 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')