Skip to content

Commit 64f70c7

Browse files
Merge pull request #230 from Azure/zhiyuanliang/refactoring
Refactor execute with failover policy code path
1 parent 83c3e11 commit 64f70c7

File tree

1 file changed

+83
-64
lines changed

1 file changed

+83
-64
lines changed

src/appConfigurationImpl.ts

Lines changed: 83 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
isFeatureFlag,
1313
isSecretReference,
1414
GetSnapshotOptions,
15+
ListConfigurationSettingsForSnapshotOptions,
1516
GetSnapshotResponse,
1617
KnownSnapshotComposition
1718
} from "@azure/app-configuration";
@@ -482,71 +483,50 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
482483
*/
483484
async #loadConfigurationSettings(loadFeatureFlag: boolean = false): Promise<ConfigurationSetting[]> {
484485
const selectors = loadFeatureFlag ? this.#ffSelectors : this.#kvSelectors;
485-
const funcToExecute = async (client) => {
486-
// Use a Map to deduplicate configuration settings by key. When multiple selectors return settings with the same key,
487-
// the configuration setting loaded by the later selector in the iteration order will override the one from the earlier selector.
488-
const loadedSettings: Map<string, ConfigurationSetting> = new Map<string, ConfigurationSetting>();
489-
// deep copy selectors to avoid modification if current client fails
490-
const selectorsToUpdate: PagedSettingsWatcher[] = JSON.parse(
491-
JSON.stringify(selectors)
492-
);
493486

494-
for (const selector of selectorsToUpdate) {
495-
if (selector.snapshotName === undefined) {
496-
const listOptions: ListConfigurationSettingsOptions = {
497-
keyFilter: selector.keyFilter,
498-
labelFilter: selector.labelFilter,
499-
tagsFilter: selector.tagFilters
500-
};
501-
const pageWatchers: SettingWatcher[] = [];
502-
const pageIterator = listConfigurationSettingsWithTrace(
503-
this.#requestTraceOptions,
504-
client,
505-
listOptions
506-
).byPage();
507-
508-
for await (const page of pageIterator) {
509-
pageWatchers.push({ etag: page.etag });
510-
for (const setting of page.items) {
511-
if (loadFeatureFlag === isFeatureFlag(setting)) {
512-
loadedSettings.set(setting.key, setting);
513-
}
514-
}
515-
}
516-
selector.pageWatchers = pageWatchers;
517-
} else { // snapshot selector
518-
const snapshot = await this.#getSnapshot(selector.snapshotName);
519-
if (snapshot === undefined) {
520-
throw new InvalidOperationError(`Could not find snapshot with name ${selector.snapshotName}.`);
521-
}
522-
if (snapshot.compositionType != KnownSnapshotComposition.Key) {
523-
throw new InvalidOperationError(`Composition type for the selected snapshot with name ${selector.snapshotName} must be 'key'.`);
524-
}
525-
const pageIterator = listConfigurationSettingsForSnapshotWithTrace(
526-
this.#requestTraceOptions,
527-
client,
528-
selector.snapshotName
529-
).byPage();
530-
531-
for await (const page of pageIterator) {
532-
for (const setting of page.items) {
533-
if (loadFeatureFlag === isFeatureFlag(setting)) {
534-
loadedSettings.set(setting.key, setting);
535-
}
536-
}
537-
}
487+
// Use a Map to deduplicate configuration settings by key. When multiple selectors return settings with the same key,
488+
// the configuration setting loaded by the later selector in the iteration order will override the one from the earlier selector.
489+
const loadedSettings: Map<string, ConfigurationSetting> = new Map<string, ConfigurationSetting>();
490+
// deep copy selectors to avoid modification if current client fails
491+
const selectorsToUpdate: PagedSettingsWatcher[] = JSON.parse(
492+
JSON.stringify(selectors)
493+
);
494+
495+
for (const selector of selectorsToUpdate) {
496+
let settings: ConfigurationSetting[] = [];
497+
if (selector.snapshotName === undefined) {
498+
const listOptions: ListConfigurationSettingsOptions = {
499+
keyFilter: selector.keyFilter,
500+
labelFilter: selector.labelFilter,
501+
tagsFilter: selector.tagFilters
502+
};
503+
const { items, pageWatchers } = await this.#listConfigurationSettings(listOptions);
504+
selector.pageWatchers = pageWatchers;
505+
settings = items;
506+
} else { // snapshot selector
507+
const snapshot = await this.#getSnapshot(selector.snapshotName);
508+
if (snapshot === undefined) {
509+
throw new InvalidOperationError(`Could not find snapshot with name ${selector.snapshotName}.`);
510+
}
511+
if (snapshot.compositionType != KnownSnapshotComposition.Key) {
512+
throw new InvalidOperationError(`Composition type for the selected snapshot with name ${selector.snapshotName} must be 'key'.`);
538513
}
514+
settings = await this.#listConfigurationSettingsForSnapshot(selector.snapshotName);
539515
}
540516

541-
if (loadFeatureFlag) {
542-
this.#ffSelectors = selectorsToUpdate;
543-
} else {
544-
this.#kvSelectors = selectorsToUpdate;
517+
for (const setting of settings) {
518+
if (loadFeatureFlag === isFeatureFlag(setting)) {
519+
loadedSettings.set(setting.key, setting);
520+
}
545521
}
546-
return Array.from(loadedSettings.values());
547-
};
522+
}
548523

549-
return await this.#executeWithFailoverPolicy(funcToExecute) as ConfigurationSetting[];
524+
if (loadFeatureFlag) {
525+
this.#ffSelectors = selectorsToUpdate;
526+
} else {
527+
this.#kvSelectors = selectorsToUpdate;
528+
}
529+
return Array.from(loadedSettings.values());
550530
}
551531

552532
/**
@@ -754,13 +734,13 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
754734
/**
755735
* Gets a configuration setting by key and label.If the setting is not found, return undefine instead of throwing an error.
756736
*/
757-
async #getConfigurationSetting(configurationSettingId: ConfigurationSettingId, customOptions?: GetConfigurationSettingOptions): Promise<GetConfigurationSettingResponse | undefined> {
737+
async #getConfigurationSetting(configurationSettingId: ConfigurationSettingId, getOptions?: GetConfigurationSettingOptions): Promise<GetConfigurationSettingResponse | undefined> {
758738
const funcToExecute = async (client) => {
759739
return getConfigurationSettingWithTrace(
760740
this.#requestTraceOptions,
761741
client,
762742
configurationSettingId,
763-
customOptions
743+
getOptions
764744
);
765745
};
766746

@@ -777,13 +757,33 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
777757
return response;
778758
}
779759

780-
async #getSnapshot(snapshotName: string, customOptions?: GetSnapshotOptions): Promise<GetSnapshotResponse | undefined> {
760+
async #listConfigurationSettings(listOptions: ListConfigurationSettingsOptions): Promise<{ items: ConfigurationSetting[]; pageWatchers: SettingWatcher[] }> {
761+
const funcToExecute = async (client) => {
762+
const pageWatchers: SettingWatcher[] = [];
763+
const pageIterator = listConfigurationSettingsWithTrace(
764+
this.#requestTraceOptions,
765+
client,
766+
listOptions
767+
).byPage();
768+
769+
const items: ConfigurationSetting[] = [];
770+
for await (const page of pageIterator) {
771+
pageWatchers.push({ etag: page.etag });
772+
items.push(...page.items);
773+
}
774+
return { items, pageWatchers };
775+
};
776+
777+
return await this.#executeWithFailoverPolicy(funcToExecute);
778+
}
779+
780+
async #getSnapshot(snapshotName: string, getOptions?: GetSnapshotOptions): Promise<GetSnapshotResponse | undefined> {
781781
const funcToExecute = async (client) => {
782782
return getSnapshotWithTrace(
783783
this.#requestTraceOptions,
784784
client,
785785
snapshotName,
786-
customOptions
786+
getOptions
787787
);
788788
};
789789

@@ -800,6 +800,25 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
800800
return response;
801801
}
802802

803+
async #listConfigurationSettingsForSnapshot(snapshotName: string, listOptions?: ListConfigurationSettingsForSnapshotOptions): Promise<ConfigurationSetting[]> {
804+
const funcToExecute = async (client) => {
805+
const pageIterator = listConfigurationSettingsForSnapshotWithTrace(
806+
this.#requestTraceOptions,
807+
client,
808+
snapshotName,
809+
listOptions
810+
).byPage();
811+
812+
const items: ConfigurationSetting[] = [];
813+
for await (const page of pageIterator) {
814+
items.push(...page.items);
815+
}
816+
return items;
817+
};
818+
819+
return await this.#executeWithFailoverPolicy(funcToExecute);
820+
}
821+
803822
// Only operations related to Azure App Configuration should be executed with failover policy.
804823
async #executeWithFailoverPolicy(funcToExecute: (client: AppConfigurationClient) => Promise<any>): Promise<any> {
805824
let clientWrappers = await this.#clientManager.getClients();
@@ -875,7 +894,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
875894
#setAIConfigurationTracing(setting: ConfigurationSetting<string>): void {
876895
if (this.#requestTracingEnabled && this.#aiConfigurationTracing !== undefined) {
877896
const contentType = parseContentType(setting.contentType);
878-
// content type: "application/json; profile=\"https://azconfig.io/mime-profiles/ai\"""
897+
// content type: "application/json; profile=\"https://azconfig.io/mime-profiles/ai\""
879898
if (isJsonContentType(contentType) &&
880899
!isFeatureFlagContentType(contentType) &&
881900
!isSecretReferenceContentType(contentType)) {

0 commit comments

Comments
 (0)