Skip to content

Commit 48505fd

Browse files
authored
Skip validation of FUNCTIONS_WORKER_RUNTIME with function metadata in placeholder mode (#10459)
* Excluding WarmUp function during placeholder mode when validating FWR with Language in funciton metadata. * Simplified the change based on PR feedback. * Cancelled another change which is needed due to simplification. * Adding a check in `ValidateAndLogRuntimeMismatch` to ensure it is called only during non placeholder mode code path. If called form placeholder mode, this method will throw now. * Checking error log level in tests.
1 parent 6bccacf commit 48505fd

File tree

4 files changed

+42
-4
lines changed

4 files changed

+42
-4
lines changed

release_notes.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88
- Update application insights agent version to 3.5.4
99
- Includes fixes from 2.16.0
1010
- Migrated Scale Metrics to use `Azure.Data.Tables` SDK (#10276)
11-
- Added support for Identity-based connections
11+
- Added support for Identity-based connections
12+
- Skip validation of `FUNCTIONS_WORKER_RUNTIME` with funciton metadata in placeholder mode. (#10459)

src/WebJobs.Script/Host/ScriptHost.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -776,8 +776,13 @@ private void TrySetDirectType(FunctionMetadata metadata)
776776
// Ensure customer deployed application payload matches with the worker runtime configured for the function app and log a warning if not.
777777
// If a customer has "dotnet-isolated" worker runtime configured for the function app, and then they deploy an in-proc app payload, this will warn/error
778778
// If there is a mismatch, the method will return false, else true.
779-
private static bool ValidateAndLogRuntimeMismatch(IEnumerable<FunctionMetadata> functionMetadata, string workerRuntime, IOptions<FunctionsHostingConfigOptions> hostingConfigOptions, ILogger logger)
779+
private bool ValidateAndLogRuntimeMismatch(IEnumerable<FunctionMetadata> functionMetadata, string workerRuntime, IOptions<FunctionsHostingConfigOptions> hostingConfigOptions, ILogger logger)
780780
{
781+
if (_environment.IsPlaceholderModeEnabled())
782+
{
783+
throw new InvalidOperationException($"Validation of '{EnvironmentSettingNames.FunctionWorkerRuntime}' with deployed payload metadata should not occur in placeholder mode.");
784+
}
785+
781786
if (functionMetadata != null && functionMetadata.Any() && !Utility.ContainsAnyFunctionMatchingWorkerRuntime(functionMetadata, workerRuntime))
782787
{
783788
var languages = string.Join(", ", functionMetadata.Select(f => f.Language).Distinct()).Replace(DotNetScriptTypes.DotNetAssembly, RpcWorkerConstants.DotNetLanguageWorkerName);
@@ -804,7 +809,7 @@ internal async Task<Collection<FunctionDescriptor>> GetFunctionDescriptorsAsync(
804809
{
805810
bool throwOnWorkerRuntimeAndPayloadMetadataMismatch = true;
806811
// this dotnet isolated specific logic is temporary to ensure in-proc payload compatibility with "dotnet-isolated" as the FUNCTIONS_WORKER_RUNTIME value.
807-
if (string.Equals(workerRuntime, RpcWorkerConstants.DotNetIsolatedLanguageWorkerName, StringComparison.OrdinalIgnoreCase))
812+
if (string.Equals(workerRuntime, RpcWorkerConstants.DotNetIsolatedLanguageWorkerName, StringComparison.OrdinalIgnoreCase) && !_environment.IsPlaceholderModeEnabled())
808813
{
809814
bool payloadMatchesWorkerRuntime = ValidateAndLogRuntimeMismatch(functions, workerRuntime, _hostingConfigOptions, _logger);
810815
if (!payloadMatchesWorkerRuntime)

test/WebJobs.Script.Tests.Integration/Host/StandbyManager/StandbyManagerE2ETests_Windows.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,38 @@ public async Task ZipPackageFailure_DetectedOnSpecialization()
7979
host.Dispose();
8080
}
8181

82+
83+
[Fact]
84+
public async Task StandbyModeE2E_DotnetIsolated_WarmupSucceeds()
85+
{
86+
_settings.Add(EnvironmentSettingNames.AzureWebsiteInstanceId, Guid.NewGuid().ToString());
87+
88+
var environment = new TestEnvironment(_settings);
89+
environment.SetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeSettingName, RpcWorkerConstants.DotNetIsolatedLanguageWorkerName);
90+
91+
await InitializeTestHostAsync("Windows", environment);
92+
93+
await VerifyWarmupSucceeds();
94+
95+
await TestHelpers.Await(() =>
96+
{
97+
// wait for the trace indicating that the host has started in placeholder mode.
98+
var logs = _loggerProvider.GetAllLogMessages().Where(p => p.FormattedMessage != null).Select(p => p.FormattedMessage).ToArray();
99+
return logs.Contains("Job host started") && logs.Contains("Host state changed from Initialized to Running.");
100+
}, userMessageCallback: () => string.Join(Environment.NewLine, _loggerProvider.GetAllLogMessages().Select(p => $"[{p.Timestamp.ToString("HH:mm:ss.fff")}] {p.FormattedMessage}")));
101+
102+
var logLines = _loggerProvider.GetAllLogMessages().Where(p => p.FormattedMessage != null).Select(p => p.FormattedMessage).ToArray();
103+
104+
Assert.Single(logLines.Where(l => l.EndsWith("[FunctionsNetHost] Starting FunctionsNetHost")));
105+
Assert.Equal(1, logLines.Count(p => p.Contains("Creating StandbyMode placeholder function directory")));
106+
Assert.Equal(1, logLines.Count(p => p.Contains("StandbyMode placeholder function directory created")));
107+
Assert.Equal(1, logLines.Count(p => p.Contains("Host is in standby mode")));
108+
109+
// Ensure no warning logs are present.
110+
var warningLogEntries = _loggerProvider.GetAllLogMessages().Where(a => a.Level == Microsoft.Extensions.Logging.LogLevel.Warning);
111+
Assert.True(!warningLogEntries.Any(), $"Warnings found in logs: {string.Join(Environment.NewLine, warningLogEntries.Select(e => e.FormattedMessage))}");
112+
}
113+
82114
[Theory]
83115
[InlineData(true)]
84116
[InlineData(false)]

test/WebJobs.Script.Tests.Integration/WebHostEndToEnd/WebJobsStartupEndToEndTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public async Task InProcAppsWorkWithDotnetIsolatedAsFunctionWorkerRuntimeValue()
6666
"which does not match the worker runtime metadata found in the deployed function app artifacts. " +
6767
"The deployed artifacts are for 'dotnet'. See https://aka.ms/functions-invalid-worker-runtime " +
6868
"for more information. The application will continue to run, but may throw an exception in the future.";
69-
Assert.Single(fixture.Host.GetScriptHostLogMessages(), p => p.FormattedMessage != null && p.FormattedMessage.EndsWith(expectedLogEntry));
69+
Assert.Single(fixture.Host.GetScriptHostLogMessages().Where(a => a.Level == Microsoft.Extensions.Logging.LogLevel.Warning), p => p.FormattedMessage != null && p.FormattedMessage.EndsWith(expectedLogEntry));
7070
}
7171
finally
7272
{

0 commit comments

Comments
 (0)