Skip to content

Commit 9d63b7c

Browse files
Merge branch 'preview' of https://github.com/Azure/AppConfiguration-JavaScriptProvider into zhiyuanliang/afd-support
2 parents 665af4c + 8f75608 commit 9d63b7c

File tree

4 files changed

+63
-17
lines changed

4 files changed

+63
-17
lines changed

package-lock.json

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"dev": "rollup --config --watch",
3131
"lint": "eslint src/ test/ examples/ --ext .js,.ts,.mjs",
3232
"fix-lint": "eslint src/ test/ examples/ --fix --ext .js,.ts,.mjs",
33-
"test": "mocha out/esm/test/cdn.test.js out/commonjs/test/cdn.test.js --parallel --timeout 100000",
33+
"test": "mocha out/esm/test/*.test.js out/commonjs/test/*.test.js --parallel --timeout 100000",
3434
"test-browser": "npx playwright install chromium && vitest --config vitest.browser.config.ts run"
3535
},
3636
"repository": {

src/appConfigurationImpl.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -621,21 +621,19 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
621621
* Updates etag of watched settings from loaded data. If a watched setting is not covered by any selector, a request will be sent to retrieve it.
622622
*/
623623
async #updateWatchedKeyValuesEtag(existingSettings: ConfigurationSetting[]): Promise<void> {
624+
const updatedSentinels: ConfigurationSettingId[] = [];
624625
for (const sentinel of this.#sentinels) {
625626
const matchedSetting = existingSettings.find(s => s.key === sentinel.key && s.label === sentinel.label);
626627
if (matchedSetting) {
627-
sentinel.etag = matchedSetting.etag;
628+
updatedSentinels.push( {...sentinel, etag: matchedSetting.etag} );
628629
} else {
629630
// Send a request to retrieve key-value since it may be either not loaded or loaded with a different label or different casing
630631
const { key, label } = sentinel;
631632
const response = await this.#getConfigurationSetting({ key, label }, { onlyIfChanged: false });
632-
if (isRestError(response)) { // watched key not found
633-
sentinel.etag = undefined;
634-
} else {
635-
sentinel.etag = response.etag;
636-
}
633+
updatedSentinels.push( {...sentinel, etag: isRestError(response) ? undefined : response.etag} );
637634
}
638635
}
636+
this.#sentinels = updatedSentinels;
639637
}
640638

641639
/**
@@ -700,7 +698,6 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
700698
sentinel.etag !== response.etag; // etag changed
701699

702700
if (isDeleted || isChanged) {
703-
sentinel.etag = isChanged ? (response as GetConfigurationSettingResponse).etag : undefined;
704701
const timestamp = this.#getResponseTimestamp(response);
705702
if (timestamp > this.#lastKvChangeDetected) {
706703
this.#lastKvChangeDetected = timestamp;

test/refresh.test.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,19 @@ function addSetting(key: string, value: any) {
2525
}
2626

2727
let listKvRequestCount = 0;
28+
let failNextListKv = false;
2829
const listKvCallback = () => {
30+
if (failNextListKv) {
31+
throw new Error("Intended error for test");
32+
}
2933
listKvRequestCount++;
3034
};
3135
let getKvRequestCount = 0;
36+
let failNextGetKv = false;
3237
const getKvCallback = () => {
38+
if (failNextGetKv) {
39+
throw new Error("Intended error for test");
40+
}
3341
getKvRequestCount++;
3442
};
3543

@@ -40,6 +48,7 @@ describe("dynamic refresh", function () {
4048
{ value: "red", key: "app.settings.fontColor" },
4149
{ value: "40", key: "app.settings.fontSize" },
4250
{ value: "30", key: "app.settings.fontSize", label: "prod" },
51+
{ value: "someValue", key: "sentinel" },
4352
{ value: "someValue", key: "TestTagKey", tags: { "env": "dev" } }
4453
].map(createMockedKeyValue);
4554
mockAppConfigurationClientListConfigurationSettings([mockedKVs], listKvCallback);
@@ -48,6 +57,8 @@ describe("dynamic refresh", function () {
4857

4958
afterEach(() => {
5059
restoreMocks();
60+
failNextListKv = false;
61+
failNextGetKv = false;
5162
listKvRequestCount = 0;
5263
getKvRequestCount = 0;
5364
});
@@ -239,6 +250,44 @@ describe("dynamic refresh", function () {
239250
expect(settings.get("app.settings.bgColor")).eq("white");
240251
});
241252

253+
it("should continue to refresh when previous refresh-all attempt failed", async () => {
254+
const connectionString = createMockedConnectionString();
255+
const settings = await load(connectionString, {
256+
selectors: [
257+
{ keyFilter: "app.settings.*" }
258+
],
259+
refreshOptions: {
260+
enabled: true,
261+
refreshIntervalInMs: 2000,
262+
watchedSettings: [
263+
{ key: "sentinel" }
264+
]
265+
}
266+
});
267+
expect(settings.get("app.settings.fontSize")).eq("40");
268+
expect(settings.get("app.settings.fontColor")).eq("red");
269+
expect(settings.get("sentinel")).to.be.undefined;
270+
expect(listKvRequestCount).eq(1);
271+
expect(getKvRequestCount).eq(1); // one getKv request for sentinel key
272+
273+
// change setting
274+
addSetting("app.settings.bgColor", "white");
275+
updateSetting("sentinel", "updatedValue");
276+
failNextListKv = true; // force next listConfigurationSettings request to fail
277+
await sleepInMs(2 * 1000 + 1);
278+
await settings.refresh(); // even if the provider detects the sentinel key change, this refresh will fail, so we won't get the updated value of sentinel
279+
expect(listKvRequestCount).eq(1);
280+
expect(getKvRequestCount).eq(2);
281+
expect(settings.get("app.settings.bgColor")).to.be.undefined;
282+
283+
failNextListKv = false;
284+
await sleepInMs(2 * 1000 + 1);
285+
await settings.refresh(); // should continue to refresh even if sentinel key doesn't change now
286+
expect(listKvRequestCount).eq(2);
287+
expect(getKvRequestCount).eq(4);
288+
expect(settings.get("app.settings.bgColor")).eq("white");
289+
});
290+
242291
it("should execute callbacks on successful refresh", async () => {
243292
const connectionString = createMockedConnectionString();
244293
const settings = await load(connectionString, {

0 commit comments

Comments
 (0)