Restart process if custom args present
MODIFY
src/WebJobs.Script/Workers/Rpc/WebHostRpcWorkerChannelManager.cs
src/WebJobs.Script/Workers/Rpc/WebHostRpcWorkerChannelManager.cs
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs.Script.Diagnostics;
using Microsoft.Azure.WebJobs.Script.Eventing;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@@ -27,10 +28,11 @@ public class WebHostRpcWorkerChannelManager : IWebHostRpcWorkerChannelManager
private readonly IMetricsLogger _metricsLogger;
private string _workerRuntime;
private Action _shutdownStandbyWorkerChannels;
+ private IConfiguration _config;
private ConcurrentDictionary<string, Dictionary<string, TaskCompletionSource<IRpcWorkerChannel>>> _workerChannels = new ConcurrentDictionary<string, Dictionary<string, TaskCompletionSource<IRpcWorkerChannel>>>(StringComparer.OrdinalIgnoreCase);
- public WebHostRpcWorkerChannelManager(IScriptEventManager eventManager, IEnvironment environment, ILoggerFactory loggerFactory, IRpcWorkerChannelFactory rpcWorkerChannelFactory, IOptionsMonitor<ScriptApplicationHostOptions> applicationHostOptions, IMetricsLogger metricsLogger, IOptionsMonitor<LanguageWorkerOptions> languageWorkerOptions)
+ public WebHostRpcWorkerChannelManager(IScriptEventManager eventManager, IEnvironment environment, ILoggerFactory loggerFactory, IRpcWorkerChannelFactory rpcWorkerChannelFactory, IOptionsMonitor<ScriptApplicationHostOptions> applicationHostOptions, IMetricsLogger metricsLogger, IOptionsMonitor<LanguageWorkerOptions> languageWorkerOptions, IConfiguration config)
{
_environment = environment ?? throw new ArgumentNullException(nameof(environment));
_eventManager = eventManager;
@@ -40,6 +42,7 @@ public WebHostRpcWorkerChannelManager(IScriptEventManager eventManager, IEnviron
_logger = loggerFactory.CreateLogger<WebHostRpcWorkerChannelManager>();
_applicationHostOptions = applicationHostOptions;
_lanuageworkerOptions = languageWorkerOptions;
+ _config = config ?? throw new ArgumentNullException(nameof(config));
_shutdownStandbyWorkerChannels = ScheduleShutdownStandbyChannels;
_shutdownStandbyWorkerChannels = _shutdownStandbyWorkerChannels.Debounce(milliseconds: 5000);
@@ -131,6 +134,13 @@ private bool UsePlaceholderChannel(string workerRuntime)
{
if (!string.IsNullOrEmpty(workerRuntime))
{
+ // Restart worker process if custom languageWorkers:[runtime]:arguments are passed in
+ var workerArguments = _config.GetSection($"{RpcWorkerConstants.LanguageWorkersSectionName}:{workerRuntime}:{WorkerConstants.WorkerDescriptionArguments}").Value;
+ if (!string.IsNullOrEmpty(workerArguments))
+ {
+ return false;
+ }
+
// Special case: node and PowerShell apps must be read-only to use the placeholder mode channel
// Also cannot use placeholder worker that is targeting ~3 but has backwards compatibility with V2 enabled
// TODO: Remove special casing when resolving https://github.com/Azure/azure-functions-host/issues/4534

MODIFY
test/WebJobs.Script.Tests/Workers/Rpc/WebHostRpcWorkerChannelManagerTests.cs
test/WebJobs.Script.Tests/Workers/Rpc/WebHostRpcWorkerChannelManagerTests.cs
using Microsoft.Azure.WebJobs.Script.Eventing;
using Microsoft.Azure.WebJobs.Script.Workers;
using Microsoft.Azure.WebJobs.Script.Workers.Rpc;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.WebJobs.Script.Tests;
@@ -32,6 +33,7 @@ public class WebHostRpcWorkerChannelManagerTests
private readonly IOptionsMonitor<LanguageWorkerOptions> _workerOptionsMonitor;
private readonly Mock<IWorkerProcess> _rpcWorkerProcess;
private readonly TestLogger _testLogger;
+ private readonly IConfiguration _emptyConfig;
private WebHostRpcWorkerChannelManager _rpcWorkerChannelManager;
@@ -68,7 +70,8 @@ public WebHostRpcWorkerChannelManagerTests()
_testLogger = new TestLogger("WebHostLanguageWorkerChannelManagerTests");
_rpcWorkerChannelFactory = new TestRpcWorkerChannelFactory(_eventManager, _testLogger, _scriptRootPath);
- _rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, new TestMetricsLogger(), _workerOptionsMonitor);
+ _emptyConfig = new ConfigurationBuilder().Build();
+ _rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, new TestMetricsLogger(), _workerOptionsMonitor, _emptyConfig);
}
[Fact]
@@ -89,7 +92,7 @@ public async Task ShutdownStandByChannels_Succeeds()
{
var testMetricsLogger = new TestMetricsLogger();
_testEnvironment.SetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeSettingName, RpcWorkerConstants.JavaLanguageWorkerName);
- _rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, testMetricsLogger, _workerOptionsMonitor);
+ _rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, testMetricsLogger, _workerOptionsMonitor, _emptyConfig);
IRpcWorkerChannel javaWorkerChannel = CreateTestChannel(RpcWorkerConstants.JavaLanguageWorkerName);
@@ -110,7 +113,7 @@ public async Task ShutdownStandByChannels_WorkerRuntinmeDotNet_Succeeds()
{
var testMetricsLogger = new TestMetricsLogger();
_testEnvironment.SetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeSettingName, RpcWorkerConstants.DotNetLanguageWorkerName);
- _rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, testMetricsLogger, _workerOptionsMonitor);
+ _rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, testMetricsLogger, _workerOptionsMonitor, _emptyConfig);
IRpcWorkerChannel javaWorkerChannel = CreateTestChannel(RpcWorkerConstants.JavaLanguageWorkerName);
IRpcWorkerChannel nodeWorkerChannel = CreateTestChannel(RpcWorkerConstants.NodeLanguageWorkerName);
@@ -149,7 +152,7 @@ public async Task ShutdownStandyChannels_WorkerRuntime_Node_Set()
{
var testMetricsLogger = new TestMetricsLogger();
_testEnvironment.SetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeSettingName, RpcWorkerConstants.NodeLanguageWorkerName);
- _rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, testMetricsLogger, _workerOptionsMonitor);
+ _rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, testMetricsLogger, _workerOptionsMonitor, _emptyConfig);
IRpcWorkerChannel javaWorkerChannel = CreateTestChannel(RpcWorkerConstants.JavaLanguageWorkerName);
@@ -170,7 +173,7 @@ public async Task SpecializeAsync_ReadOnly_KeepsProcessAlive(string runtime, str
_testEnvironment.SetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeSettingName, runtime);
_testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteZipDeployment, "1");
- _rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, testMetricsLogger, _workerOptionsMonitor);
+ _rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, testMetricsLogger, _workerOptionsMonitor, _emptyConfig);
IRpcWorkerChannel workerChannel = CreateTestChannel(languageWorkerName);
@@ -199,7 +202,7 @@ public async Task SpecializeAsync_Java_KeepsProcessAlive()
_testEnvironment.SetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeSettingName, RpcWorkerConstants.JavaLanguageWorkerName);
_testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteZipDeployment, "0");
- _rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, testMetricsLogger, _workerOptionsMonitor);
+ _rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, testMetricsLogger, _workerOptionsMonitor, _emptyConfig);
IRpcWorkerChannel javaWorkerChannel = CreateTestChannel(RpcWorkerConstants.JavaLanguageWorkerName);
@@ -229,7 +232,7 @@ public async Task SpecializeAsync_Java_ReadOnly_KeepsProcessAlive()
_testEnvironment.SetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeSettingName, RpcWorkerConstants.JavaLanguageWorkerName);
_testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteZipDeployment, "1");
- _rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, testMetricsLogger, _workerOptionsMonitor);
+ _rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, testMetricsLogger, _workerOptionsMonitor, _emptyConfig);
IRpcWorkerChannel javaWorkerChannel = CreateTestChannel(RpcWorkerConstants.JavaLanguageWorkerName);
@@ -262,7 +265,40 @@ public async Task SpecializeAsync_NotReadOnly_KillsProcess(string languageWorker
// This is an invalid setting configuration, but just to show that run from zip is NOT set
_testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteZipDeployment, "0");
- _rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, testMetricsLogger, _workerOptionsMonitor);
+ _rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, testMetricsLogger, _workerOptionsMonitor, _emptyConfig);
+
+ IRpcWorkerChannel workerChannel = CreateTestChannel(languageWorkerName);
+
+ await _rpcWorkerChannelManager.SpecializeAsync();
+
+ // Verify logs
+ var traces = _testLogger.GetLogMessages();
+ Assert.True(traces.Count() == 0);
+
+ // Verify channel
+ var initializedChannel = await _rpcWorkerChannelManager.GetChannelAsync(languageWorkerName);
+ Assert.Null(initializedChannel);
+ }
+
+ [Theory]
+ [InlineData(RpcWorkerConstants.NodeLanguageWorkerName, "--inspect 9800")]
+ [InlineData(RpcWorkerConstants.PowerShellLanguageWorkerName, "-force")]
+ [InlineData(RpcWorkerConstants.PythonLanguageWorkerName, "-i input")]
+ [InlineData(RpcWorkerConstants.JavaLanguageWorkerName, "-D")]
+ public async Task SpecializeAsync_LanguageWorkerArguments_KillsProcess(string languageWorkerName, string argument)
+ {
+ var testMetricsLogger = new TestMetricsLogger();
+ _testEnvironment.SetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeSettingName, languageWorkerName);
+ _testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.FunctionsExtensionVersion, "~3");
+ _testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteZipDeployment, "1");
+
+ var config = new ConfigurationBuilder()
+ .AddInMemoryCollection(new Dictionary<string, string>
+ {
+ [$"{RpcWorkerConstants.LanguageWorkersSectionName}:{languageWorkerName}:{WorkerConstants.WorkerDescriptionArguments}"] = argument
+ })
+ .Build();
+ _rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, testMetricsLogger, _workerOptionsMonitor, config);
IRpcWorkerChannel workerChannel = CreateTestChannel(languageWorkerName);
@@ -287,7 +323,7 @@ public async Task SpecializeAsync_Node_V2CompatibilityWithV3Extension_KillsProce
_testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.FunctionsV2CompatibilityModeKey, "true");
_testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.FunctionsExtensionVersion, "~3");
- _rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, testMetricsLogger, _workerOptionsMonitor);
+ _rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, _rpcWorkerChannelFactory, _optionsMonitor, testMetricsLogger, _workerOptionsMonitor, _emptyConfig);
IRpcWorkerChannel workerChannel = CreateTestChannel(languageWorkerName);
@@ -362,7 +398,7 @@ public async Task ShutdownChannelsIfExistsAsync_StopsWorkerInvocations()
public async Task InitializeLanguageWorkerChannel_ThrowsOnProcessStartup()
{
var rpcWorkerChannelFactory = new TestRpcWorkerChannelFactory(_eventManager, null, _scriptRootPath, throwOnProcessStartUp: true);
- var rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, rpcWorkerChannelFactory, _optionsMonitor, new TestMetricsLogger(), _workerOptionsMonitor);
+ var rpcWorkerChannelManager = new WebHostRpcWorkerChannelManager(_eventManager, _testEnvironment, _loggerFactory, rpcWorkerChannelFactory, _optionsMonitor, new TestMetricsLogger(), _workerOptionsMonitor, _emptyConfig);
var rpcWorkerChannel = await rpcWorkerChannelManager.InitializeLanguageWorkerChannel("test", _scriptRootPath);
var ex = await Assert.ThrowsAsync<AggregateException>(async () => await rpcWorkerChannelManager.GetChannelAsync("test"));
Assert.Contains("Process startup failed", ex.InnerException.Message);

Restart process if custom args present (#7259)