Skip to content

Commit d8e8c6c

Browse files
support snapshot reference
1 parent 64f70c7 commit d8e8c6c

File tree

3 files changed

+64
-10
lines changed

3 files changed

+64
-10
lines changed

src/appConfigurationImpl.ts

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
8282
#featureFlagTracing: FeatureFlagTracingOptions | undefined;
8383
#fmVersion: string | undefined;
8484
#aiConfigurationTracing: AIConfigurationTracingOptions | undefined;
85+
#useSnapshotReference: boolean = false;
8586

8687
// Refresh
8788
#refreshInProgress: boolean = false;
@@ -213,7 +214,8 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
213214
isFailoverRequest: this.#isFailoverRequest,
214215
featureFlagTracing: this.#featureFlagTracing,
215216
fmVersion: this.#fmVersion,
216-
aiConfigurationTracing: this.#aiConfigurationTracing
217+
aiConfigurationTracing: this.#aiConfigurationTracing,
218+
useSnapshotReference: this.#useSnapshotReference
217219
};
218220
}
219221

@@ -504,17 +506,26 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
504506
selector.pageWatchers = pageWatchers;
505507
settings = items;
506508
} 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'.`);
513-
}
514-
settings = await this.#listConfigurationSettingsForSnapshot(selector.snapshotName);
509+
settings = await this.#loadConfigurationSettingsFromSnapshot(selector.snapshotName);
515510
}
516511

517512
for (const setting of settings) {
513+
if (isSnapshotReference(setting) && !loadFeatureFlag) {
514+
this.#useSnapshotReference = true;
515+
516+
// TODO: When SDK supports snapshot reference, use the helper method from SDK.
517+
const snapshotName = parseSnapshotReference(setting).value.snapshotName;
518+
const settingsFromSnapshot = await this.#loadConfigurationSettingsFromSnapshot(snapshotName);
519+
520+
for (const snapshotSetting of settingsFromSnapshot) {
521+
if (!isFeatureFlag(snapshotSetting)) {
522+
// Feature flags inside snapshot are ignored. This is consistent the behavior that key value selectors ignore feature flags.
523+
loadedSettings.set(snapshotSetting.key, snapshotSetting);
524+
}
525+
}
526+
continue;
527+
}
528+
518529
if (loadFeatureFlag === isFeatureFlag(setting)) {
519530
loadedSettings.set(setting.key, setting);
520531
}
@@ -575,6 +586,18 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
575586
}
576587
}
577588

589+
async #loadConfigurationSettingsFromSnapshot(snapshotName: string): Promise<ConfigurationSetting[]> {
590+
const snapshot = await this.#getSnapshot(snapshotName);
591+
if (snapshot === undefined) {
592+
throw new InvalidOperationError(`Could not find snapshot with name ${snapshotName}.`);
593+
}
594+
if (snapshot.compositionType != KnownSnapshotComposition.Key) {
595+
throw new InvalidOperationError(`Composition type for the selected snapshot with name ${snapshotName} must be 'key'.`);
596+
}
597+
const settings: ConfigurationSetting[] = await this.#listConfigurationSettingsForSnapshot(snapshotName);
598+
return settings;
599+
}
600+
578601
/**
579602
* Clears all existing key-values in the local configuration except feature flags.
580603
*/
@@ -1068,3 +1091,28 @@ function validateTagFilters(tagFilters: string[]): void {
10681091
}
10691092
}
10701093
}
1094+
1095+
// TODO: Temporary workaround until SDK supports snapshot reference
1096+
const snapshotReferenceContentType = "application/json; profile=\"https://azconfig.io/mime-profiles/snapshot-ref\"; charset=utf-8";
1097+
1098+
interface JsonSnapshotReferenceValue {
1099+
snapshot_name: string;
1100+
}
1101+
1102+
function isSnapshotReference(setting: ConfigurationSetting):
1103+
setting is ConfigurationSetting & Required<Pick<ConfigurationSetting, "value">> {
1104+
return (setting && setting.contentType === snapshotReferenceContentType && typeof setting.value === "string");
1105+
}
1106+
1107+
function parseSnapshotReference(setting: ConfigurationSetting) {
1108+
if (!isSnapshotReference(setting)) {
1109+
throw new Error(`Invalid snapshot reference: ${setting}`);
1110+
}
1111+
const jsonSnapshotReferenceValue = JSON.parse(setting.value) as JsonSnapshotReferenceValue;
1112+
1113+
const snapshotReference = {
1114+
...setting,
1115+
value: { snapshotName: jsonSnapshotReferenceValue.snapshot_name },
1116+
};
1117+
return snapshotReference;
1118+
}

src/requestTracing/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export const REPLICA_COUNT_KEY = "ReplicaCount";
5151
export const KEY_VAULT_CONFIGURED_TAG = "UsesKeyVault";
5252
export const KEY_VAULT_REFRESH_CONFIGURED_TAG = "RefreshesKeyVault";
5353
export const FAILOVER_REQUEST_TAG = "Failover";
54+
export const SNAPSHOT_REFERENCE_TAG = "SnapshotRef";
5455

5556
// Compact feature tags
5657
export const FEATURES_KEY = "Features";

src/requestTracing/utils.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ import {
4141
FM_VERSION_KEY,
4242
DELIMITER,
4343
AI_CONFIGURATION_TAG,
44-
AI_CHAT_COMPLETION_CONFIGURATION_TAG
44+
AI_CHAT_COMPLETION_CONFIGURATION_TAG,
45+
SNAPSHOT_REFERENCE_TAG
4546
} from "./constants.js";
4647

4748
export interface RequestTracingOptions {
@@ -53,6 +54,7 @@ export interface RequestTracingOptions {
5354
featureFlagTracing: FeatureFlagTracingOptions | undefined;
5455
fmVersion: string | undefined;
5556
aiConfigurationTracing: AIConfigurationTracingOptions | undefined;
57+
useSnapshotReference: boolean;
5658
}
5759

5860
// Utils
@@ -195,6 +197,9 @@ function createFeaturesString(requestTracingOptions: RequestTracingOptions): str
195197
if (requestTracingOptions.aiConfigurationTracing?.usesAIChatCompletionConfiguration) {
196198
tags.push(AI_CHAT_COMPLETION_CONFIGURATION_TAG);
197199
}
200+
if (requestTracingOptions.useSnapshotReference) {
201+
tags.push(SNAPSHOT_REFERENCE_TAG);
202+
}
198203
return tags.join(DELIMITER);
199204
}
200205

0 commit comments

Comments
 (0)