|
4 | 4 | *--------------------------------------------------------------------------------------------*/ |
5 | 5 |
|
6 | 6 | import type { StringDictionary } from '@azure/arm-appservice'; |
7 | | -import type { ParsedSite } from '@microsoft/vscode-azext-azureappservice'; |
| 7 | +import type { ParsedSite, SiteClient } from '@microsoft/vscode-azext-azureappservice'; |
8 | 8 | import { IActionContext } from '@microsoft/vscode-azext-utils'; |
| 9 | +import * as retry from 'p-retry'; |
9 | 10 | import * as vscode from 'vscode'; |
10 | | -import { azureWebJobsFeatureFlags, ConnectionKey, ConnectionKeyValues, DurableBackend, DurableBackendValues, extensionVersionKey, ProjectLanguage, runFromPackageKey, workerRuntimeKey } from '../../constants'; |
11 | | -import { ext } from '../../extensionVariables'; |
12 | 11 | import { FuncVersion, tryParseFuncVersion } from '../../FuncVersion'; |
| 12 | +import { ConnectionKey, ConnectionKeyValues, DurableBackend, DurableBackendValues, ProjectLanguage, azureWebJobsFeatureFlags, extensionVersionKey, runFromPackageKey, workerRuntimeKey } from '../../constants'; |
| 13 | +import { ext } from '../../extensionVariables'; |
13 | 14 | import { localize } from '../../localize'; |
14 | 15 | import { SlotTreeItem } from '../../tree/SlotTreeItem'; |
15 | 16 | import { isNodeV4Plus, isPythonV2Plus } from '../../utils/programmingModelUtils'; |
@@ -57,6 +58,12 @@ export async function verifyAppSettings(options: { |
57 | 58 |
|
58 | 59 | if (updateAppSettings) { |
59 | 60 | await client.updateApplicationSettings(appSettings); |
| 61 | + try { |
| 62 | + await verifyAppSettingsPropagated(context, client, appSettings); |
| 63 | + } catch (e) { |
| 64 | + // don't throw if we can't verify the settings were updated |
| 65 | + } |
| 66 | + |
60 | 67 | // if the user cancels the deployment, the app settings node doesn't reflect the updated settings |
61 | 68 | await node.appSettingsTreeItem?.refresh(context); |
62 | 69 | } |
@@ -202,3 +209,32 @@ function verifyFeatureFlagSetting(context: IActionContext, site: ParsedSite, rem |
202 | 209 | context.telemetry.properties.addedFeatureFlagSetting = String(shouldAddSetting); |
203 | 210 | return shouldAddSetting; |
204 | 211 | } |
| 212 | + |
| 213 | +// App settings are not always propagated before the deployment leading to an inconsistent behavior so verify that |
| 214 | +async function verifyAppSettingsPropagated(context: IActionContext, client: SiteClient, expectedAppSettings: StringDictionary): Promise<void> { |
| 215 | + const expectedProperties = expectedAppSettings.properties || {}; |
| 216 | + // Retry up to 2 minutes |
| 217 | + const retries = 12; |
| 218 | + |
| 219 | + return await retry( |
| 220 | + async (attempt: number) => { |
| 221 | + context.telemetry.measurements.verifyAppSettingsPropagatedAttempt = attempt; |
| 222 | + ext.outputChannel.appendLog(localize('verifyAppSettings', `Verifying that app settings have propagated... (Attempt ${attempt}/${retries})`), { resourceName: client.fullName }); |
| 223 | + |
| 224 | + const currentAppSettings = await client.listApplicationSettings(); |
| 225 | + const currentProperties = currentAppSettings.properties || {}; |
| 226 | + // we need to check the union of the keys because we may have removed properties as well |
| 227 | + const keysUnion = new Set([...Object.keys(expectedProperties), ...Object.keys(currentProperties)]); |
| 228 | + |
| 229 | + for (const key of keysUnion) { |
| 230 | + if (currentProperties[key] !== expectedProperties[key]) { |
| 231 | + // error gets swallowed by the end so no need for an error message |
| 232 | + throw new Error(); |
| 233 | + } |
| 234 | + } |
| 235 | + |
| 236 | + return; |
| 237 | + }, |
| 238 | + { retries, minTimeout: 10 * 1000 } |
| 239 | + ); |
| 240 | +} |
0 commit comments