Skip to content

Commit cf277a9

Browse files
authored
Set same default retry options with other providers (#7)
1 parent cc0d337 commit cf277a9

File tree

3 files changed

+115
-4
lines changed

3 files changed

+115
-4
lines changed

src/AzureAppConfigurationOptions.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
import { AppConfigurationClientOptions } from "@azure/app-configuration";
55
import { AzureAppConfigurationKeyVaultOptions } from "./keyvault/AzureAppConfigurationKeyVaultOptions";
66

7+
export const MaxRetries = 2;
8+
export const MaxRetryDelayInMs = 60000;
9+
710
export interface AzureAppConfigurationOptions {
811
selectors?: { keyFilter: string, labelFilter: string }[];
912
trimKeyPrefixes?: string[];

src/Load.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { AppConfigurationClient, AppConfigurationClientOptions } from "@azure/ap
55
import { TokenCredential } from "@azure/identity";
66
import { AzureAppConfiguration } from "./AzureAppConfiguration";
77
import { AzureAppConfigurationImpl } from "./AzureAppConfigurationImpl";
8-
import { AzureAppConfigurationOptions } from "./AzureAppConfigurationOptions";
8+
import { AzureAppConfigurationOptions, MaxRetries, MaxRetryDelayInMs } from "./AzureAppConfigurationOptions";
99

1010
export async function load(connectionString: string, options?: AzureAppConfigurationOptions): Promise<AzureAppConfiguration>;
1111
export async function load(endpoint: URL | string, credential: TokenCredential, options?: AzureAppConfigurationOptions): Promise<AzureAppConfiguration>;
@@ -52,9 +52,16 @@ function instanceOfTokenCredential(obj: unknown) {
5252
return obj && typeof obj === "object" && "getToken" in obj && typeof obj.getToken === "function";
5353
}
5454

55-
function getClientOptions(options?: AzureAppConfigurationOptions): AppConfigurationClientOptions | undefined{
55+
function getClientOptions(options?: AzureAppConfigurationOptions): AppConfigurationClientOptions | undefined {
5656
// TODO: user-agent
5757
// TODO: set correlation context using additional policies
58-
// TODO: allow override default retry options
59-
return options?.clientOptions;
58+
// retry options
59+
const defaultRetryOptions = {
60+
maxRetries: MaxRetries,
61+
maxRetryDelayInMs: MaxRetryDelayInMs,
62+
}
63+
const retryOptions = Object.assign({}, defaultRetryOptions, options?.clientOptions?.retryOptions);
64+
return Object.assign({}, options?.clientOptions, {
65+
retryOptions
66+
});
6067
}

test/clientOptions.test.js

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
4+
const chai = require("chai");
5+
const chaiAsPromised = require("chai-as-promised");
6+
chai.use(chaiAsPromised);
7+
const expect = chai.expect;
8+
const { load } = require("../dist/index");
9+
const { createMockedConnectionString } = require("./utils/testHelper");
10+
const nock = require('nock');
11+
12+
class HttpRequestCountPolicy {
13+
constructor() {
14+
this.count = 0;
15+
this.name = "HttpRequestCountPolicy";
16+
}
17+
sendRequest(req, next) {
18+
this.count++;
19+
return next(req).then(resp => { resp.status = 500; return resp; });
20+
}
21+
resetCount() {
22+
this.count = 0;
23+
}
24+
};
25+
26+
describe("custom client options", function () {
27+
const fakeEndpoint = "https://azure.azconfig.io";
28+
before(() => {
29+
// Thus here mock it to reply 500, in which case the retry mechanism works.
30+
nock(fakeEndpoint).persist().get(() => true).reply(500);
31+
});
32+
33+
after(() => {
34+
nock.restore();
35+
})
36+
37+
it("should retry 2 times by default", async () => {
38+
const countPolicy = new HttpRequestCountPolicy();
39+
const loadPromise = () => {
40+
return load(createMockedConnectionString(fakeEndpoint), {
41+
clientOptions: {
42+
additionalPolicies: [{
43+
policy: countPolicy,
44+
position: "perRetry"
45+
}]
46+
}
47+
})
48+
};
49+
let error;
50+
try {
51+
await loadPromise();
52+
} catch (e) {
53+
error = e;
54+
}
55+
expect(error).not.undefined;
56+
expect(countPolicy.count).eq(3);
57+
});
58+
59+
it("should override default retry options", async () => {
60+
const countPolicy = new HttpRequestCountPolicy();
61+
const loadWithMaxRetries = (maxRetries) => {
62+
return load(createMockedConnectionString(fakeEndpoint), {
63+
clientOptions: {
64+
additionalPolicies: [{
65+
policy: countPolicy,
66+
position: "perRetry"
67+
}],
68+
retryOptions: {
69+
maxRetries
70+
}
71+
}
72+
})
73+
};
74+
75+
let error;
76+
try {
77+
error = undefined;
78+
await loadWithMaxRetries(0);
79+
} catch (e) {
80+
error = e;
81+
}
82+
expect(error).not.undefined;
83+
expect(countPolicy.count).eq(1);
84+
85+
countPolicy.resetCount();
86+
try {
87+
error = undefined;
88+
await loadWithMaxRetries(1);
89+
} catch (e) {
90+
error = e;
91+
}
92+
expect(error).not.undefined;
93+
expect(countPolicy.count).eq(2);
94+
});
95+
96+
// Note:
97+
// core-rest-pipeline skips the retry throwing `RestError: getaddrinfo ENOTFOUND azure.azconfig.io`
98+
// Probably would be fixed in upstream libs.
99+
// See https://github.com/Azure/azure-sdk-for-js/issues/27037
100+
it("should retry on DNS failure");
101+
})

0 commit comments

Comments
 (0)