From 859cab7d98387640a57a2e32f926d2ee839f05c5 Mon Sep 17 00:00:00 2001 From: peze <954152927@qq.com> Date: Thu, 28 Mar 2024 18:10:49 +0800 Subject: [PATCH] upgrade retry time --- src/error.ts | 4 +- src/retry.ts | 20 ++++++-- test/fixtures/test.txt | 1 + test/retry.spec.ts | 112 +++++++++++++++++++++++++++++++++++------ 4 files changed, 117 insertions(+), 20 deletions(-) diff --git a/src/error.ts b/src/error.ts index d77df50..4164d5c 100644 --- a/src/error.ts +++ b/src/error.ts @@ -14,9 +14,10 @@ export class BaseError extends Error { } } -class ResponseError extends BaseError { +export class ResponseError extends BaseError { code: string statusCode: number + retryAfter: number data: any description: string accessDeniedDetail: any @@ -26,6 +27,7 @@ class ResponseError extends BaseError { this.name = 'ResponseError'; this.data = map.data; this.description = map.description; + this.retryAfter = map.retryAfter; this.accessDeniedDetail = map.accessDeniedDetail; if (this.data && this.data.statusCode) { this.statusCode = Number(this.data.statusCode); diff --git a/src/retry.ts b/src/retry.ts index a8d9c77..1eb0c32 100644 --- a/src/retry.ts +++ b/src/retry.ts @@ -1,5 +1,7 @@ import * as $core from './core'; import * as $error from './error'; +const MAX_DELAY_TIME = 120 * 1000; +const MIN_DELAY_TIME = 100; export class BackoffPolicy{ policy: string; constructor(option: {[key: string]: any}) { @@ -116,11 +118,13 @@ export class RetryCondition { backoff: BackoffPolicy; exception: string[]; errorCode: string[]; + maxDelay: number; constructor(condition: {[key: string]: any}) { this.maxAttempts = condition.maxAttempts; this.backoff = condition.backoff && BackoffPolicy.newBackoffPolicy(condition.backoff); this.exception = condition.exception; this.errorCode = condition.errorCode; + this.maxDelay = condition.maxDelay; } } @@ -146,7 +150,7 @@ export class RetryPolicyContext { retriesAttempted: number; httpRequest: $core.Request; httpResponse: $core.Response; - exception: $error.BaseError; + exception: $error.ResponseError | $error.BaseError; constructor(options: {[key: string]: any}) { this.key = options.key; this.retriesAttempted = options.retriesAttempted || 0; @@ -183,7 +187,7 @@ export function shouldRetry(options: RetryOptions, ctx: RetryPolicyContext): boo return false; } -export function getBackoffDealy(options: RetryOptions, ctx: RetryPolicyContext): number { +export function getBackoffDelay(options: RetryOptions, ctx: RetryPolicyContext): number { const ex = ctx.exception; const conditions = options.retryCondition; for(let i = 0; i < conditions.length; i++) { @@ -191,10 +195,16 @@ export function getBackoffDealy(options: RetryOptions, ctx: RetryPolicyContext): if(!condition.exception.includes(ex.name) && !condition.errorCode.includes(ex.code)) { continue; } + const maxDelay = condition.maxDelay || MAX_DELAY_TIME; + const retryAfter = (ctx.exception as $error.ResponseError).retryAfter; + if(retryAfter !== undefined) { + return Math.min(retryAfter, maxDelay); + } + if(!condition.backoff) { - return 100; + return MIN_DELAY_TIME; } - return condition.backoff.getDelayTime(ctx); + return Math.min(condition.backoff.getDelayTime(ctx), maxDelay); } - return 100; + return MIN_DELAY_TIME; } \ No newline at end of file diff --git a/test/fixtures/test.txt b/test/fixtures/test.txt index e69de29..74ecff1 100644 --- a/test/fixtures/test.txt +++ b/test/fixtures/test.txt @@ -0,0 +1 @@ +Test For File \ No newline at end of file diff --git a/test/retry.spec.ts b/test/retry.spec.ts index 53a5e6e..ed4838b 100644 --- a/test/retry.spec.ts +++ b/test/retry.spec.ts @@ -20,6 +20,14 @@ describe('$dara retry', function () { } } + class CErr extends $dara.ResponseError { + + constructor(map: { [key: string]: any }) { + super(map); + this.name = 'BErr'; + } + } + it('init base backoff policy should not okay', function() { try { const err = new $dara.BackoffPolicy({}); @@ -139,7 +147,7 @@ describe('$dara retry', function () { assert.deepStrictEqual($dara.shouldRetry(option, context), false); }); - it('getBackoffDealy should ok', async function () { + it('getBackoffDelay should ok', async function () { const condition = new $dara.RetryCondition({ maxAttempts: 3, exception: ['AErr'], @@ -158,7 +166,7 @@ describe('$dara retry', function () { }) }); - assert.deepStrictEqual($dara.getBackoffDealy(option, context), 100); + assert.deepStrictEqual($dara.getBackoffDelay(option, context), 100); context = new $dara.RetryPolicyContext({ retriesAttempted: 2, @@ -168,7 +176,7 @@ describe('$dara retry', function () { }) }); - assert.deepStrictEqual($dara.getBackoffDealy(option, context), 100); + assert.deepStrictEqual($dara.getBackoffDelay(option, context), 100); const fixedPolicy = $dara.BackoffPolicy.newBackoffPolicy({ policy: 'Fixed', @@ -193,7 +201,7 @@ describe('$dara retry', function () { }); - assert.deepStrictEqual($dara.getBackoffDealy(option, context), 1000); + assert.deepStrictEqual($dara.getBackoffDelay(option, context), 1000); const randomPolicy = $dara.BackoffPolicy.newBackoffPolicy({ policy: 'Random', @@ -212,7 +220,7 @@ describe('$dara retry', function () { retryCondition: [condition2] }); - assert.ok($dara.getBackoffDealy(option, context) < 10000); + assert.ok($dara.getBackoffDelay(option, context) < 10000); const randomPolicy2 = $dara.BackoffPolicy.newBackoffPolicy({ policy: 'Random', @@ -231,7 +239,7 @@ describe('$dara retry', function () { retryCondition: [condition2Other] }); - assert.deepStrictEqual($dara.getBackoffDealy(option, context), 10); + assert.deepStrictEqual($dara.getBackoffDelay(option, context), 10); let exponentialPolicy = $dara.BackoffPolicy.newBackoffPolicy({ @@ -251,7 +259,7 @@ describe('$dara retry', function () { retryCondition: [condition3] }); - assert.deepStrictEqual($dara.getBackoffDealy(option, context), 1024); + assert.deepStrictEqual($dara.getBackoffDelay(option, context), 1024); exponentialPolicy = $dara.BackoffPolicy.newBackoffPolicy({ policy: 'Exponential', @@ -270,7 +278,7 @@ describe('$dara retry', function () { retryCondition: [condition4] }); - assert.deepStrictEqual($dara.getBackoffDealy(option, context), 10000); + assert.deepStrictEqual($dara.getBackoffDelay(option, context), 10000); let equalJitterPolicy = $dara.BackoffPolicy.newBackoffPolicy({ policy: 'EqualJitter', @@ -279,7 +287,7 @@ describe('$dara retry', function () { }); const condition5 = new $dara.RetryCondition({ - maxAttempts: 3, + maxAttempts: 2, exception: ['AErr'], errorCode: ['A1Err'], backoff: equalJitterPolicy, @@ -288,7 +296,7 @@ describe('$dara retry', function () { retryable: true, retryCondition: [condition5] }); - let backoffTime = $dara.getBackoffDealy(option, context) + let backoffTime = $dara.getBackoffDelay(option, context) assert.ok(backoffTime > 512 && backoffTime < 1024); equalJitterPolicy = $dara.BackoffPolicy.newBackoffPolicy({ @@ -307,7 +315,7 @@ describe('$dara retry', function () { retryable: true, retryCondition: [condition6] }); - backoffTime = $dara.getBackoffDealy(option, context) + backoffTime = $dara.getBackoffDelay(option, context) assert.ok(backoffTime > 5000 && backoffTime < 10000); @@ -318,7 +326,7 @@ describe('$dara retry', function () { }); const condition7 = new $dara.RetryCondition({ - maxAttempts: 3, + maxAttempts: 2, exception: ['AErr'], errorCode: ['A1Err'], backoff: fullJitterPolicy, @@ -327,7 +335,7 @@ describe('$dara retry', function () { retryable: true, retryCondition: [condition7] }); - backoffTime = $dara.getBackoffDealy(option, context) + backoffTime = $dara.getBackoffDelay(option, context) assert.ok(backoffTime >= 0 && backoffTime < 1024); fullJitterPolicy = $dara.BackoffPolicy.newBackoffPolicy({ @@ -346,7 +354,83 @@ describe('$dara retry', function () { retryable: true, retryCondition: [condition8] }); - backoffTime = $dara.getBackoffDealy(option, context) + backoffTime = $dara.getBackoffDelay(option, context) assert.ok(backoffTime >= 0 && backoffTime < 10000); + + const condition9 = new $dara.RetryCondition({ + maxAttempts: 3, + exception: ['AErr'], + errorCode: ['A1Err'], + backoff: fullJitterPolicy, + maxDelay: 1000, + }); + option = new $dara.RetryOptions({ + retryable: true, + retryCondition: [condition9] + }); + backoffTime = $dara.getBackoffDelay(option, context) + assert.ok(backoffTime >= 0 && backoffTime <= 1000); + + + fullJitterPolicy = $dara.BackoffPolicy.newBackoffPolicy({ + policy: 'ExponentialWithFullJitter', + period: 100, + cap: 10000 * 10000, + }); + + const condition12 = new $dara.RetryCondition({ + maxAttempts: 2, + exception: ['AErr'], + errorCode: ['A1Err'], + backoff: fullJitterPolicy, + }); + option = new $dara.RetryOptions({ + retryable: true, + retryCondition: [condition12] + }); + backoffTime = $dara.getBackoffDelay(option, context); + assert.ok(backoffTime >= 0 && backoffTime <= 120 * 1000); + + context = new $dara.RetryPolicyContext({ + retriesAttempted: 2, + exception: new CErr({ + code: 'CErr', + message: 'c error', + retryAfter: 3000 + }) + }); + const condition10 = new $dara.RetryCondition({ + maxAttempts: 3, + exception: ['CErr'], + errorCode: ['CErr'], + backoff: fullJitterPolicy, + maxDelay: 5000, + }); + option = new $dara.RetryOptions({ + retryable: true, + retryCondition: [condition10] + }); + backoffTime = $dara.getBackoffDelay(option, context) + assert.strictEqual(backoffTime, 3000); + + const condition11 = new $dara.RetryCondition({ + maxAttempts: 3, + exception: ['CErr'], + errorCode: ['CErr'], + backoff: fullJitterPolicy, + maxDelay: 1000, + }); + option = new $dara.RetryOptions({ + retryable: true, + retryCondition: [condition11] + }); + backoffTime = $dara.getBackoffDelay(option, context) + assert.strictEqual(backoffTime, 1000); + + + }); + + + }); \ No newline at end of file