Skip to content

Commit 7de8a0d

Browse files
update
1 parent fc1aa5b commit 7de8a0d

File tree

4 files changed

+23
-24
lines changed

4 files changed

+23
-24
lines changed

src/AzureAppConfigurationImpl.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ import { RequestTracingOptions, getConfigurationSettingWithTrace, listConfigurat
4141
import { FeatureFlagTracingOptions } from "./requestTracing/FeatureFlagTracingOptions.js";
4242
import { KeyFilter, LabelFilter, SettingSelector } from "./types.js";
4343
import { ConfigurationClientManager } from "./ConfigurationClientManager.js";
44-
import { getFixedBackoffDuration, calculateDynamicBackoffDuration } from "./failover.js";
45-
import { FailoverError, OperationError, isFailoverableError, isRetriableError } from "./error.js";
44+
import { getFixedBackoffDuration, calculateBackoffDuration } from "./failover.js";
45+
import { OperationError, isFailoverableError, isRetriableError } from "./error.js";
4646

4747
type PagedSettingSelector = SettingSelector & {
4848
/**
@@ -357,7 +357,6 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
357357
this.#isInitialLoadCompleted = true;
358358
break;
359359
} catch (error) {
360-
361360
if (!isRetriableError(error)) {
362361
throw error;
363362
}
@@ -369,7 +368,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
369368
let backoffDuration = getFixedBackoffDuration(timeElapsed);
370369
if (backoffDuration === undefined) {
371370
postAttempts += 1;
372-
backoffDuration = calculateDynamicBackoffDuration(postAttempts);
371+
backoffDuration = calculateBackoffDuration(postAttempts);
373372
}
374373
await new Promise(resolve => setTimeout(resolve, backoffDuration));
375374
console.warn("Failed to load configuration settings at startup. Retrying...");
@@ -697,7 +696,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
697696
}
698697

699698
this.#clientManager.refreshClients();
700-
throw new FailoverError("All fallback clients failed to get configuration settings.");
699+
throw new Error("All fallback clients failed to get configuration settings.");
701700
}
702701

703702
async #processKeyValues(setting: ConfigurationSetting<string>): Promise<[string, unknown]> {

src/ConfigurationClientWrapper.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Licensed under the MIT license.
33

44
import { AppConfigurationClient } from "@azure/app-configuration";
5-
import { calculateDynamicBackoffDuration } from "./failover.js";
5+
import { calculateBackoffDuration } from "./failover.js";
66

77
export class ConfigurationClientWrapper {
88
endpoint: string;
@@ -21,7 +21,7 @@ export class ConfigurationClientWrapper {
2121
this.backoffEndTime = Date.now();
2222
} else {
2323
this.#failedAttempts += 1;
24-
this.backoffEndTime = Date.now() + calculateDynamicBackoffDuration(this.#failedAttempts);
24+
this.backoffEndTime = Date.now() + calculateBackoffDuration(this.#failedAttempts);
2525
}
2626
}
2727
}

src/error.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,21 @@ export class OperationError extends Error {
1313
}
1414
}
1515

16-
/**
17-
* Error thrown when fail to perform failover.
18-
*/
19-
export class FailoverError extends Error {
20-
constructor(message: string) {
21-
super(message);
22-
this.name = "FailoverError";
23-
}
24-
}
25-
2616
export function isFailoverableError(error: any): boolean {
17+
if (!isRestError(error)) {
18+
return false;
19+
}
2720
// ENOTFOUND: DNS lookup failed, ENOENT: no such file or directory
28-
return isRestError(error) && (error.code === "ENOTFOUND" || error.code === "ENOENT" ||
29-
(error.statusCode !== undefined && (error.statusCode === 401 || error.statusCode === 403 || error.statusCode === 408 || error.statusCode === 429 || error.statusCode >= 500)));
21+
if (error.code == "ENOTFOUND" || error.code === "ENOENT"){
22+
return true;
23+
}
24+
// 401 Unauthorized, 403 Forbidden, 408 Request Timeout, 429 Too Many Requests, 5xx Server Errors
25+
if (error.statusCode !== undefined &&
26+
(error.statusCode === 401 || error.statusCode === 403 || error.statusCode === 408 || error.statusCode === 429 || error.statusCode >= 500)) {
27+
return true;
28+
}
29+
30+
return false;
3031
}
3132

3233
export function isRetriableError(error: any): boolean {

src/failover.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33

44
const MIN_BACKOFF_DURATION = 30_000; // 30 seconds in milliseconds
55
const MAX_BACKOFF_DURATION = 10 * 60 * 1000; // 10 minutes in milliseconds
6-
const MAX_SAFE_EXPONENTIAL = 30; // Used to avoid overflow. bitwise operations in JavaScript are limited to 32 bits. It overflows at 2^31 - 1.
76
const JITTER_RATIO = 0.25;
87

9-
// Reference: https://github.com/Azure/AppConfiguration-DotnetProvider/blob/main/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/Extensions/TimeSpanExtensions.cs#L14
8+
// The backoff duration algorithm is consistent with the .NET configuration provider's implementation.
109
export function getFixedBackoffDuration(timeElapsed: number): number | undefined {
1110
if (timeElapsed <= 100_000) { // 100 seconds in milliseconds
1211
return 5_000; // 5 seconds in milliseconds
@@ -20,14 +19,14 @@ export function getFixedBackoffDuration(timeElapsed: number): number | undefined
2019
return undefined;
2120
}
2221

23-
export function calculateDynamicBackoffDuration(failedAttempts: number) {
22+
export function calculateBackoffDuration(failedAttempts: number) {
2423
if (failedAttempts <= 1) {
2524
return MIN_BACKOFF_DURATION;
2625
}
2726

2827
// exponential: minBackoff * 2 ^ (failedAttempts - 1)
29-
const exponential = Math.min(failedAttempts - 1, MAX_SAFE_EXPONENTIAL);
30-
let calculatedBackoffDuration = MIN_BACKOFF_DURATION * (1 << exponential);
28+
// The right shift operator is not used in order to avoid potential overflow. Bitwise operations in JavaScript are limited to 32 bits.
29+
let calculatedBackoffDuration = MIN_BACKOFF_DURATION * Math.pow(2, failedAttempts - 1);
3130
if (calculatedBackoffDuration > MAX_BACKOFF_DURATION) {
3231
calculatedBackoffDuration = MAX_BACKOFF_DURATION;
3332
}

0 commit comments

Comments
 (0)