Skip to content

Commit d8dee3b

Browse files
support snapshot reference
1 parent de7781a commit d8dee3b

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
*/
@@ -1071,3 +1094,28 @@ function validateTagFilters(tagFilters: string[]): void {
10711094
}
10721095
}
10731096
}
1097+
1098+
// TODO: Temporary workaround until SDK supports snapshot reference
1099+
const snapshotReferenceContentType = "application/json; profile=\"https://azconfig.io/mime-profiles/snapshot-ref\"; charset=utf-8";
1100+
1101+
interface JsonSnapshotReferenceValue {
1102+
snapshot_name: string;
1103+
}
1104+
1105+
function isSnapshotReference(setting: ConfigurationSetting):
1106+
setting is ConfigurationSetting & Required<Pick<ConfigurationSetting, "value">> {
1107+
return (setting && setting.contentType === snapshotReferenceContentType && typeof setting.value === "string");
1108+
}
1109+
1110+
function parseSnapshotReference(setting: ConfigurationSetting) {
1111+
if (!isSnapshotReference(setting)) {
1112+
throw new Error(`Invalid snapshot reference: ${setting}`);
1113+
}
1114+
const jsonSnapshotReferenceValue = JSON.parse(setting.value) as JsonSnapshotReferenceValue;
1115+
1116+
const snapshotReference = {
1117+
...setting,
1118+
value: { snapshotName: jsonSnapshotReferenceValue.snapshot_name },
1119+
};
1120+
return snapshotReference;
1121+
}

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)