diff --git a/release_notes.md b/release_notes.md index 99bd2089df..1b36d51189 100644 --- a/release_notes.md +++ b/release_notes.md @@ -2,4 +2,5 @@ \ No newline at end of file +--> +- Allow sync trigger to happen in managed environment when `AzureWebJobsStorage` is not set (#11214) diff --git a/src/WebJobs.Script.WebHost/Management/FunctionsSyncManager.cs b/src/WebJobs.Script.WebHost/Management/FunctionsSyncManager.cs index 08c8cbc81d..e640e67a09 100644 --- a/src/WebJobs.Script.WebHost/Management/FunctionsSyncManager.cs +++ b/src/WebJobs.Script.WebHost/Management/FunctionsSyncManager.cs @@ -114,7 +114,7 @@ public async Task TrySyncTriggersAsync(bool isBackgroundSync PrepareSyncTriggers(); var hashBlobClient = await GetHashBlobAsync(); - if (isBackgroundSync && hashBlobClient == null && !_environment.IsKubernetesManagedHosting()) + if (isBackgroundSync && hashBlobClient == null && !_environment.IsAnyKubernetesEnvironment()) { // short circuit before doing any work in background sync // cases where we need to check/update hash but don't have @@ -135,7 +135,7 @@ public async Task TrySyncTriggersAsync(bool isBackgroundSync bool shouldSyncTriggers = true; string newHash = null; - if (isBackgroundSync && !_environment.IsKubernetesManagedHosting()) + if (isBackgroundSync && hashBlobClient != null) { newHash = await CheckHashAsync(hashBlobClient, payload.Content); shouldSyncTriggers = newHash != null; diff --git a/test/WebJobs.Script.Tests.Integration/Management/FunctionsSyncManagerTests.cs b/test/WebJobs.Script.Tests.Integration/Management/FunctionsSyncManagerTests.cs index 6076f0d283..c1b428f124 100644 --- a/test/WebJobs.Script.Tests.Integration/Management/FunctionsSyncManagerTests.cs +++ b/test/WebJobs.Script.Tests.Integration/Management/FunctionsSyncManagerTests.cs @@ -299,6 +299,62 @@ public async Task TrySyncTriggers_LocalEnvironment_ReturnsFalse() } } + [Fact] + public async Task TrySyncTriggers_ManagedAppEnv_WithNo_AzureWebJobsStorage_ReturnsTrue() + { + _vars.Add("AzureWebJobsStorage", null); + _mockEnvironment.Setup(p => p.GetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteArmCacheEnabled)).Returns("0"); + + using (var env = new TestScopedEnvironmentVariable(_vars)) + { + _mockEnvironment.Setup(p => p.GetEnvironmentVariable(EnvironmentSettingNames.ManagedEnvironment)).Returns("true"); + _mockEnvironment.Setup(p => p.GetEnvironmentVariable("FUNCTIONS_API_SERVER")).Returns("https://appname.azurewebsites.net"); + _mockEnvironment.Setup(p => p.GetEnvironmentVariable("CONTAINER_APP_NAME")).Returns("appname"); + _mockEnvironment.Setup(p => p.GetEnvironmentVariable("CONTAINER_APP_NAMESPACE")).Returns("appns"); + _mockEnvironment.Setup(p => p.GetEnvironmentVariable("CONTAINER_APP_REVISION")).Returns("appname--r1"); + + // _functionsSyncManager is initialized in the constructor with all the secrets from environment, + // so HostAzureBlobStorageProvider will have AzureWebJobsStorage defined in both ActiveHostConfigurationSource + // and the WebHost IConfiguration source from DI. + // The TestScopedEnvironmentVariable only changes the WebHost level IConfiguration + // When it is set to empty/null, the connection string from the ActiveHostConfigurationSource wins (never changed since it is set in + // constructor as mentioned). + // Therefore, we need to force refresh the configuration with an ActiveHostChanged event. This is because setting an empty/null environment variable + // removes it, but will not remove it from the ActiveHostConfigurationSource. + _scriptHostManager.OnActiveHostChanged(); + var result = await _functionsSyncManager.TrySyncTriggersAsync(isBackgroundSync: true); + Assert.True(result.Success); + VerifyResultWithCacheOff(durableVersion: "V1"); + } + } + + [Fact] + public async Task TrySyncTriggers_KubernetesManagedEnv_WithNo_AzureWebJobsStorage_ReturnsTrue() + { + _vars.Add("AzureWebJobsStorage", null); + _mockEnvironment.Setup(p => p.GetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteArmCacheEnabled)).Returns("0"); + + using (var env = new TestScopedEnvironmentVariable(_vars)) + { + _mockEnvironment.Setup(p => p.GetEnvironmentVariable("FUNCTIONS_API_SERVER")).Returns("https://appname.azurewebsites.net"); + _mockEnvironment.Setup(p => p.GetEnvironmentVariable("KUBERNETES_SERVICE_HOST")).Returns("kubhost"); + _mockEnvironment.Setup(p => p.GetEnvironmentVariable("POD_NAMESPACE")).Returns("podns"); + + // _functionsSyncManager is initialized in the constructor with all the secrets from environment, + // so HostAzureBlobStorageProvider will have AzureWebJobsStorage defined in both ActiveHostConfigurationSource + // and the WebHost IConfiguration source from DI. + // The TestScopedEnvironmentVariable only changes the WebHost level IConfiguration + // When it is set to empty/null, the connection string from the ActiveHostConfigurationSource wins (never changed since it is set in + // constructor as mentioned). + // Therefore, we need to force refresh the configuration with an ActiveHostChanged event. This is because setting an empty/null environment variable + // removes it, but will not remove it from the ActiveHostConfigurationSource. + _scriptHostManager.OnActiveHostChanged(); + var result = await _functionsSyncManager.TrySyncTriggersAsync(isBackgroundSync: true); + Assert.True(result.Success); + VerifyResultWithCacheOff(durableVersion: "V1"); + } + } + [Fact] public void ArmCacheEnabled_VerifyDefault() { @@ -1147,4 +1203,4 @@ public void Reset() } } } -} \ No newline at end of file +}