Skip to content

Commit 89ca803

Browse files
authored
[Porting Fix] Do not use cached worker option when creating worker channel (#5973)
1 parent 601f899 commit 89ca803

14 files changed

+51
-38
lines changed

src/WebJobs.Script/Host/ScriptHost.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ public class ScriptHost : JobHost, IScriptJobHost
5252
private readonly IFileLoggingStatusManager _fileLoggingStatusManager;
5353
private readonly IHostIdProvider _hostIdProvider;
5454
private readonly IHttpRoutesManager _httpRoutesManager;
55-
private readonly IEnumerable<RpcWorkerConfig> _workerConfigs;
5655
private readonly IMetricsLogger _metricsLogger = null;
5756
private readonly string _hostLogPath;
5857
private readonly Stopwatch _stopwatch = new Stopwatch();
@@ -83,7 +82,6 @@ public class ScriptHost : JobHost, IScriptJobHost
8382
// Map from BindingType to the Assembly Qualified Type name for its IExtensionConfigProvider object.
8483

8584
public ScriptHost(IOptions<JobHostOptions> options,
86-
IOptions<LanguageWorkerOptions> languageWorkerOptions,
8785
IOptions<HttpWorkerOptions> httpWorkerOptions,
8886
IEnvironment environment,
8987
IJobHostContextFactory jobHostContextFactory,
@@ -123,7 +121,6 @@ public ScriptHost(IOptions<JobHostOptions> options,
123121
_applicationLifetime = applicationLifetime;
124122
_hostIdProvider = hostIdProvider;
125123
_httpRoutesManager = httpRoutesManager;
126-
_workerConfigs = languageWorkerOptions.Value.WorkerConfigs;
127124
_isHttpWorker = httpWorkerOptions.Value.Description != null;
128125
ScriptOptions = scriptHostOptions.Value;
129126
_scriptHostManager = scriptHostManager;

src/WebJobs.Script/ScriptHostBuilderExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ public static IHostBuilder AddScriptHostCore(this IHostBuilder builder, ScriptAp
161161
services.AddSingleton<IOptionsMonitor<ScriptApplicationHostOptions>>(new ScriptApplicationHostOptionsMonitor(applicationHostOptions));
162162
services.ConfigureOptions<ScriptHostOptionsSetup>();
163163
services.ConfigureOptions<JobHostFunctionTimeoutOptionsSetup>();
164-
// TODO: pgopa only add this to WebHostServiceCollection
164+
// LanguageWorkerOptionsSetup should be registered in WebHostServiceCollection as well to enable starting worker processing in placeholder mode.
165165
services.ConfigureOptions<LanguageWorkerOptionsSetup>();
166166
services.ConfigureOptions<HttpWorkerOptionsSetup>();
167167
services.ConfigureOptions<ManagedDependencyOptionsSetup>();

src/WebJobs.Script/Workers/FunctionInvocationDispatcherFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public FunctionInvocationDispatcherFactory(IOptions<ScriptJobHostOptions> script
2525
IHttpWorkerChannelFactory httpWorkerChannelFactory,
2626
IRpcWorkerChannelFactory rpcWorkerChannelFactory,
2727
IOptions<HttpWorkerOptions> httpWorkerOptions,
28-
IOptions<LanguageWorkerOptions> rpcWorkerOptions,
28+
IOptionsMonitor<LanguageWorkerOptions> rpcWorkerOptions,
2929
IEnvironment environment,
3030
IWebHostRpcWorkerChannelManager webHostLanguageWorkerChannelManager,
3131
IJobHostRpcWorkerChannelManager jobHostLanguageWorkerChannelManager,

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public RpcFunctionInvocationDispatcher(IOptions<ScriptJobHostOptions> scriptHost
5858
IScriptEventManager eventManager,
5959
ILoggerFactory loggerFactory,
6060
IRpcWorkerChannelFactory rpcWorkerChannelFactory,
61-
IOptions<LanguageWorkerOptions> languageWorkerOptions,
61+
IOptionsMonitor<LanguageWorkerOptions> languageWorkerOptions,
6262
IWebHostRpcWorkerChannelManager webHostLanguageWorkerChannelManager,
6363
IJobHostRpcWorkerChannelManager jobHostLanguageWorkerChannelManager,
6464
IOptions<ManagedDependencyOptions> managedDependencyOptions,
@@ -71,7 +71,7 @@ public RpcFunctionInvocationDispatcher(IOptions<ScriptJobHostOptions> scriptHost
7171
_webHostLanguageWorkerChannelManager = webHostLanguageWorkerChannelManager;
7272
_jobHostLanguageWorkerChannelManager = jobHostLanguageWorkerChannelManager;
7373
_eventManager = eventManager;
74-
_workerConfigs = languageWorkerOptions.Value.WorkerConfigs;
74+
_workerConfigs = languageWorkerOptions.CurrentValue.WorkerConfigs;
7575
_managedDependencyOptions = managedDependencyOptions ?? throw new ArgumentNullException(nameof(managedDependencyOptions));
7676
_logger = loggerFactory.CreateLogger<RpcFunctionInvocationDispatcher>();
7777
_rpcWorkerChannelFactory = rpcWorkerChannelFactory;
@@ -113,7 +113,7 @@ internal async void InitializeJobhostLanguageWorkerChannelAsync()
113113

114114
internal Task InitializeJobhostLanguageWorkerChannelAsync(int attemptCount)
115115
{
116-
var rpcWorkerChannel = _rpcWorkerChannelFactory.Create(_scriptOptions.RootScriptPath, _workerRuntime, _metricsLogger, attemptCount);
116+
var rpcWorkerChannel = _rpcWorkerChannelFactory.Create(_scriptOptions.RootScriptPath, _workerRuntime, _metricsLogger, attemptCount, _workerConfigs);
117117
rpcWorkerChannel.SetupFunctionInvocationBuffers(_functions);
118118
_jobHostLanguageWorkerChannelManager.AddChannel(rpcWorkerChannel);
119119
rpcWorkerChannel.StartWorkerProcessAsync().ContinueWith(workerInitTask =>
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System.Collections.Generic;
45
using Microsoft.Azure.WebJobs.Script.Diagnostics;
56

67
namespace Microsoft.Azure.WebJobs.Script.Workers.Rpc
78
{
89
public interface IRpcWorkerChannelFactory
910
{
10-
IRpcWorkerChannel Create(string scriptRootPath, string language, IMetricsLogger metricsLogger, int attemptCount);
11+
IRpcWorkerChannel Create(string scriptRootPath, string language, IMetricsLogger metricsLogger, int attemptCount, IEnumerable<RpcWorkerConfig> workerConfigs);
1112
}
1213
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ internal RpcWorkerChannel(
109109

110110
internal IWorkerProcess WorkerProcess => _rpcWorkerProcess;
111111

112+
internal RpcWorkerConfig Config => _workerConfig;
113+
112114
public bool IsChannelReadyForInvocations()
113115
{
114116
return !_disposing && !_disposed && _state.HasFlag(RpcWorkerChannelState.InvocationBuffersInitialized | RpcWorkerChannelState.Initialized);

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
using Microsoft.Azure.WebJobs.Script.Abstractions;
99
using Microsoft.Azure.WebJobs.Script.Diagnostics;
1010
using Microsoft.Azure.WebJobs.Script.Eventing;
11-
using Microsoft.Azure.WebJobs.Script.ManagedDependencies;
1211
using Microsoft.Extensions.Logging;
1312
using Microsoft.Extensions.Options;
1413

@@ -19,22 +18,20 @@ public class RpcWorkerChannelFactory : IRpcWorkerChannelFactory
1918
private readonly ILoggerFactory _loggerFactory = null;
2019
private readonly IRpcWorkerProcessFactory _rpcWorkerProcessFactory = null;
2120
private readonly IScriptEventManager _eventManager = null;
22-
private readonly IEnumerable<RpcWorkerConfig> _workerConfigs = null;
2321
private readonly IOptionsMonitor<ScriptApplicationHostOptions> _applicationHostOptions = null;
2422

25-
public RpcWorkerChannelFactory(IScriptEventManager eventManager, IEnvironment environment, IRpcServer rpcServer, ILoggerFactory loggerFactory, IOptions<LanguageWorkerOptions> languageWorkerOptions,
23+
public RpcWorkerChannelFactory(IScriptEventManager eventManager, IEnvironment environment, IRpcServer rpcServer, ILoggerFactory loggerFactory, IOptionsMonitor<LanguageWorkerOptions> languageWorkerOptions,
2624
IOptionsMonitor<ScriptApplicationHostOptions> applicationHostOptions, IRpcWorkerProcessFactory rpcWorkerProcessManager)
2725
{
2826
_eventManager = eventManager;
2927
_loggerFactory = loggerFactory;
30-
_workerConfigs = languageWorkerOptions.Value.WorkerConfigs;
3128
_rpcWorkerProcessFactory = rpcWorkerProcessManager;
3229
_applicationHostOptions = applicationHostOptions;
3330
}
3431

35-
public IRpcWorkerChannel Create(string scriptRootPath, string runtime, IMetricsLogger metricsLogger, int attemptCount)
32+
public IRpcWorkerChannel Create(string scriptRootPath, string runtime, IMetricsLogger metricsLogger, int attemptCount, IEnumerable<RpcWorkerConfig> workerConfigs)
3633
{
37-
var languageWorkerConfig = _workerConfigs.Where(c => c.Description.Language.Equals(runtime, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
34+
var languageWorkerConfig = workerConfigs.Where(c => c.Description.Language.Equals(runtime, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
3835
if (languageWorkerConfig == null)
3936
{
4037
throw new InvalidOperationException($"WorkerCofig for runtime: {runtime} not found");

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class WebHostRpcWorkerChannelManager : IWebHostRpcWorkerChannelManager
1919
private readonly ILogger _logger = null;
2020
private readonly TimeSpan workerInitTimeout = TimeSpan.FromSeconds(30);
2121
private readonly IOptionsMonitor<ScriptApplicationHostOptions> _applicationHostOptions = null;
22+
private readonly IOptionsMonitor<LanguageWorkerOptions> _lanuageworkerOptions = null;
2223
private readonly IScriptEventManager _eventManager = null;
2324
private readonly IEnvironment _environment;
2425
private readonly ILoggerFactory _loggerFactory = null;
@@ -29,7 +30,7 @@ public class WebHostRpcWorkerChannelManager : IWebHostRpcWorkerChannelManager
2930

3031
private ConcurrentDictionary<string, Dictionary<string, TaskCompletionSource<IRpcWorkerChannel>>> _workerChannels = new ConcurrentDictionary<string, Dictionary<string, TaskCompletionSource<IRpcWorkerChannel>>>(StringComparer.OrdinalIgnoreCase);
3132

32-
public WebHostRpcWorkerChannelManager(IScriptEventManager eventManager, IEnvironment environment, ILoggerFactory loggerFactory, IRpcWorkerChannelFactory rpcWorkerChannelFactory, IOptionsMonitor<ScriptApplicationHostOptions> applicationHostOptions, IMetricsLogger metricsLogger)
33+
public WebHostRpcWorkerChannelManager(IScriptEventManager eventManager, IEnvironment environment, ILoggerFactory loggerFactory, IRpcWorkerChannelFactory rpcWorkerChannelFactory, IOptionsMonitor<ScriptApplicationHostOptions> applicationHostOptions, IMetricsLogger metricsLogger, IOptionsMonitor<LanguageWorkerOptions> languageWorkerOptions)
3334
{
3435
_environment = environment ?? throw new ArgumentNullException(nameof(environment));
3536
_eventManager = eventManager;
@@ -38,6 +39,7 @@ public WebHostRpcWorkerChannelManager(IScriptEventManager eventManager, IEnviron
3839
_rpcWorkerChannelFactory = rpcWorkerChannelFactory;
3940
_logger = loggerFactory.CreateLogger<WebHostRpcWorkerChannelManager>();
4041
_applicationHostOptions = applicationHostOptions;
42+
_lanuageworkerOptions = languageWorkerOptions;
4143

4244
_shutdownStandbyWorkerChannels = ScheduleShutdownStandbyChannels;
4345
_shutdownStandbyWorkerChannels = _shutdownStandbyWorkerChannels.Debounce(milliseconds: 5000);
@@ -56,7 +58,7 @@ internal async Task<IRpcWorkerChannel> InitializeLanguageWorkerChannel(string ru
5658
_logger.LogDebug("Creating language worker channel for runtime:{runtime}", runtime);
5759
try
5860
{
59-
rpcWorkerChannel = _rpcWorkerChannelFactory.Create(scriptRootPath, runtime, _metricsLogger, 0);
61+
rpcWorkerChannel = _rpcWorkerChannelFactory.Create(scriptRootPath, runtime, _metricsLogger, 0, _lanuageworkerOptions.CurrentValue.WorkerConfigs);
6062
AddOrUpdateWorkerChannels(runtime, rpcWorkerChannel);
6163
await rpcWorkerChannel.StartWorkerProcessAsync().ContinueWith(processStartTask =>
6264
{

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,4 +236,4 @@ await TestHelpers.Await(() =>
236236
Assert.Equal(0, result.Count());
237237
}
238238
}
239-
}
239+
}

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

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ public async Task Specialization_ResetsSharedLoadContext()
219219
}
220220

221221
[Fact]
222-
public async Task StartAsync_SetsCorrectActiveHost()
222+
public async Task StartAsync_SetsCorrectActiveHost_RefreshesLanguageWorkerOptions()
223223
{
224224
var builder = CreateStandbyHostBuilder();
225225

@@ -229,27 +229,40 @@ public async Task StartAsync_SetsCorrectActiveHost()
229229
Task ignore = Task.Delay(3000).ContinueWith(_ => _pauseAfterStandbyHostBuild.Release());
230230

231231
IWebHost host = builder.Build();
232-
var manager = host.Services.GetService<WebJobsScriptHostService>();
232+
var scriptHostService = host.Services.GetService<WebJobsScriptHostService>();
233+
var channelFactory = host.Services.GetService<IRpcWorkerChannelFactory>();
234+
var workerOptionsPlaceholderMode = host.Services.GetService<IOptions<LanguageWorkerOptions>>();
235+
Assert.Equal(4, workerOptionsPlaceholderMode.Value.WorkerConfigs.Count);
236+
var rpcChannelInPlaceholderMode = (RpcWorkerChannel)channelFactory.Create("/", "python", null, 0, workerOptionsPlaceholderMode.Value.WorkerConfigs);
237+
Assert.Equal("3.6", rpcChannelInPlaceholderMode.Config.Description.DefaultRuntimeVersion);
238+
233239

234240
// TestServer will block in the constructor so pull out the StandbyManager and use it
235241
// directly for this test.
236242
var standbyManager = host.Services.GetService<IStandbyManager>();
237243

238-
var standbyStart = Task.Run(async () => await manager.StartAsync(CancellationToken.None));
244+
var standbyStart = Task.Run(async () => await scriptHostService.StartAsync(CancellationToken.None));
239245

240246
// Wait until we've completed the build once. The standby host is built and now waiting for
241247
// _pauseAfterHostBuild to release it.
242248
await TestHelpers.Await(() => _buildCount.CurrentCount == 1);
243249

244250
_environment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteContainerReady, "1");
245-
_environment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsitePlaceholderMode, "0");
251+
_environment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsitePlaceholderMode, "0");
252+
_environment.SetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeSettingName, "python");
253+
_environment.SetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeVersionSettingName, "3.7");
246254

247255
var specializeTask = Task.Run(async () => await standbyManager.SpecializeHostAsync());
248256

249257
await Task.WhenAll(standbyStart, specializeTask);
250258

251-
var options = manager.Services.GetService<IOptions<ScriptJobHostOptions>>();
259+
var options = scriptHostService.Services.GetService<IOptions<ScriptJobHostOptions>>();
252260
Assert.Equal(_specializedScriptRoot, options.Value.RootScriptPath);
261+
262+
var workerOptionsAtJobhostLevel = scriptHostService.Services.GetService<IOptions<LanguageWorkerOptions>>();
263+
Assert.Equal(1, workerOptionsAtJobhostLevel.Value.WorkerConfigs.Count);
264+
var rpcChannelAfterSpecialization = (RpcWorkerChannel)channelFactory.Create("/", "python", null, 0, workerOptionsAtJobhostLevel.Value.WorkerConfigs);
265+
Assert.Equal("3.7", rpcChannelAfterSpecialization.Config.Description.DefaultRuntimeVersion);
253266
}
254267

255268
private IWebHostBuilder CreateStandbyHostBuilder(params string[] functions)

0 commit comments

Comments
 (0)