Skip to content

Commit 2c830a0

Browse files
authored
Fix for unhealthy host restart (#9851)
1 parent 47411df commit 2c830a0

File tree

6 files changed

+35
-5
lines changed

6 files changed

+35
-5
lines changed

src/WebJobs.Script/Config/FunctionsHostingConfigOptions.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,22 @@ public bool WorkerIndexingEnabled
4343
}
4444
}
4545

46+
/// <summary>
47+
/// Gets or Sets a value indicating whether the host should shutdown webhost worker channels during shutdown.
48+
/// </summary>
49+
public bool ShutdownWebhostWorkerChannelsOnHostShutdown
50+
{
51+
get
52+
{
53+
return GetFeatureOrDefault(RpcWorkerConstants.ShutdownWebhostWorkerChannelsOnHostShutdown, "1") == "1";
54+
}
55+
56+
set
57+
{
58+
_features[RpcWorkerConstants.ShutdownWebhostWorkerChannelsOnHostShutdown] = value ? "1" : "0";
59+
}
60+
}
61+
4662
/// <summary>
4763
/// Gets or sets a value indicating whether SWT tokens should be accepted.
4864
/// </summary>

src/WebJobs.Script/Workers/FunctionInvocationDispatcherFactory.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using Microsoft.AspNetCore.Hosting;
6+
using Microsoft.Azure.WebJobs.Script.Config;
67
using Microsoft.Azure.WebJobs.Script.Diagnostics;
78
using Microsoft.Azure.WebJobs.Script.Eventing;
89
using Microsoft.Azure.WebJobs.Script.ManagedDependencies;
@@ -31,7 +32,8 @@ public FunctionInvocationDispatcherFactory(IOptions<ScriptJobHostOptions> script
3132
IJobHostRpcWorkerChannelManager jobHostLanguageWorkerChannelManager,
3233
IOptions<ManagedDependencyOptions> managedDependencyOptions,
3334
IRpcFunctionInvocationDispatcherLoadBalancer functionDispatcherLoadBalancer,
34-
IOptions<WorkerConcurrencyOptions> workerConcurrencyOptions)
35+
IOptions<WorkerConcurrencyOptions> workerConcurrencyOptions,
36+
IOptions<FunctionsHostingConfigOptions> hostingConfigOptions)
3537
{
3638
if (httpWorkerOptions.Value == null)
3739
{
@@ -55,7 +57,8 @@ public FunctionInvocationDispatcherFactory(IOptions<ScriptJobHostOptions> script
5557
jobHostLanguageWorkerChannelManager,
5658
managedDependencyOptions,
5759
functionDispatcherLoadBalancer,
58-
workerConcurrencyOptions);
60+
workerConcurrencyOptions,
61+
hostingConfigOptions);
5962
}
6063

6164
public IFunctionInvocationDispatcher GetFunctionDispatcher() => _functionDispatcher;

src/WebJobs.Script/Workers/Rpc/FunctionRegistration/RpcFunctionInvocationDispatcher.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using System.Threading.Tasks.Dataflow;
1212
using Microsoft.AspNetCore.Hosting;
1313
using Microsoft.Azure.WebJobs.Logging;
14+
using Microsoft.Azure.WebJobs.Script.Config;
1415
using Microsoft.Azure.WebJobs.Script.Description;
1516
using Microsoft.Azure.WebJobs.Script.Diagnostics;
1617
using Microsoft.Azure.WebJobs.Script.Eventing;
@@ -36,6 +37,7 @@ internal class RpcFunctionInvocationDispatcher : IFunctionInvocationDispatcher
3637
private readonly IOptions<WorkerConcurrencyOptions> _workerConcurrencyOptions;
3738
private readonly IEnumerable<RpcWorkerConfig> _workerConfigs;
3839
private readonly Lazy<Task<int>> _maxProcessCount;
40+
private readonly IOptions<FunctionsHostingConfigOptions> _hostingConfigOptions;
3941

4042
private IScriptEventManager _eventManager;
4143
private IWebHostRpcWorkerChannelManager _webHostLanguageWorkerChannelManager;
@@ -69,7 +71,8 @@ public RpcFunctionInvocationDispatcher(IOptions<ScriptJobHostOptions> scriptHost
6971
IJobHostRpcWorkerChannelManager jobHostLanguageWorkerChannelManager,
7072
IOptions<ManagedDependencyOptions> managedDependencyOptions,
7173
IRpcFunctionInvocationDispatcherLoadBalancer functionDispatcherLoadBalancer,
72-
IOptions<WorkerConcurrencyOptions> workerConcurrencyOptions)
74+
IOptions<WorkerConcurrencyOptions> workerConcurrencyOptions,
75+
IOptions<FunctionsHostingConfigOptions> hostingConfigOptions)
7376
{
7477
_metricsLogger = metricsLogger;
7578
_scriptOptions = scriptHostOptions.Value;
@@ -85,6 +88,7 @@ public RpcFunctionInvocationDispatcher(IOptions<ScriptJobHostOptions> scriptHost
8588
_workerRuntime = _environment.GetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeSettingName);
8689
_functionDispatcherLoadBalancer = functionDispatcherLoadBalancer;
8790
_workerConcurrencyOptions = workerConcurrencyOptions;
91+
_hostingConfigOptions = hostingConfigOptions;
8892
State = FunctionInvocationDispatcherState.Default;
8993

9094
_workerErrorSubscription = _eventManager.OfType<WorkerErrorEvent>().Subscribe(WorkerError);
@@ -683,6 +687,10 @@ public void PreShutdown()
683687
{
684688
_logger.LogDebug($"Preventing any new worker processes from starting during shutdown.");
685689
_processStartCancellationToken.Cancel();
690+
if (_hostingConfigOptions.Value.ShutdownWebhostWorkerChannelsOnHostShutdown && !_scriptOptions.IsStandbyConfiguration)
691+
{
692+
ShutdownWebhostLanguageWorkerChannels();
693+
}
686694
}
687695
}
688696
}

src/WebJobs.Script/Workers/Rpc/RpcWorkerConstants.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ public static class RpcWorkerConstants
8585
public const string WorkerIndexingEnabled = "WORKER_INDEXING_ENABLED";
8686
public const string WorkerIndexingDisabledApps = "WORKER_INDEXING_DISABLED_APPS";
8787
public const string RevertWorkerShutdownBehavior = "REVERT_WORKER_SHUTDOWN_BEHAVIOR";
88+
public const string ShutdownWebhostWorkerChannelsOnHostShutdown = "ShutdownWebhostWorkerChannelsOnHostShutdown";
8889
public const string ThrowOnMissingFunctionsWorkerRuntime = "THROW_ON_MISSING_FUNCTIONS_WORKER_RUNTIME";
8990
}
9091
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public SamplesEndToEndTests_Node_MultipleProcessesNoBundle(MultiplepleProcessesT
3434
_settingsManager = ScriptSettingsManager.Instance;
3535
}
3636

37-
[Fact(Skip = "https://github.com/Azure/azure-functions-host/issues")]
37+
[Fact]
3838
public async Task NodeProcessNoBundleConfigured_Different_AfterHostRestart()
3939
{
4040
await SamplesTestHelpers.InvokeAndValidateHttpTrigger(_fixture, "HttpTrigger");

test/WebJobs.Script.Tests/Workers/Rpc/RpcFunctionInvocationDispatcherTests.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Threading;
99
using System.Threading.Tasks;
1010
using Microsoft.AspNetCore.Hosting;
11+
using Microsoft.Azure.WebJobs.Script.Config;
1112
using Microsoft.Azure.WebJobs.Script.Description;
1213
using Microsoft.Azure.WebJobs.Script.Diagnostics;
1314
using Microsoft.Azure.WebJobs.Script.Eventing;
@@ -696,7 +697,8 @@ private static RpcFunctionInvocationDispatcher GetTestFunctionDispatcher(int max
696697
jobHostLanguageWorkerChannelManager,
697698
new OptionsWrapper<ManagedDependencyOptions>(new ManagedDependencyOptions()),
698699
mockFunctionDispatcherLoadBalancer.Object,
699-
Options.Create(new WorkerConcurrencyOptions()));
700+
Options.Create(new WorkerConcurrencyOptions()),
701+
Options.Create(new FunctionsHostingConfigOptions()));
700702
}
701703

702704
private async Task<int> WaitForJobhostWorkerChannelsToStartup(RpcFunctionInvocationDispatcher functionDispatcher, int expectedCount, bool allReadyForInvocations = true)

0 commit comments

Comments
 (0)