Skip to content

Commit 0f6871b

Browse files
authored
Register profile manager at webhost scope (#8779)
1 parent 8ff9df2 commit 0f6871b

17 files changed

+250
-77
lines changed

src/WebJobs.Script/ScriptHostBuilderExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ public static void AddCommonServices(IServiceCollection services)
340340
services.AddSingleton<HostIdValidator>();
341341
services.AddSingleton<IHostIdProvider, ScriptHostIdProvider>();
342342
services.TryAddSingleton<IScriptEventManager, ScriptEventManager>();
343+
services.AddSingleton<IWorkerProfileManager, WorkerProfileManager>();
343344

344345
// Add Language Worker Service
345346
// Need to maintain the order: Add RpcInitializationService before core script host services

src/WebJobs.Script/Workers/Profiles/WorkerDescriptionProfile.cs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,17 +70,18 @@ public bool EvaluateConditions()
7070
}
7171

7272
/// <summary>
73-
/// Overrides the worker description parameters to that available in the profile
73+
/// Creates a new worker description and overrides parameters with those available in the profile
7474
/// </summary>
75-
public RpcWorkerDescription ApplyProfile(RpcWorkerDescription workerDescription)
75+
public RpcWorkerDescription ApplyProfile(RpcWorkerDescription defaultWorkerDescription)
7676
{
77-
workerDescription.Arguments = UseProfileOrDefault(ProfileDescription.Arguments, workerDescription.Arguments);
78-
workerDescription.DefaultExecutablePath = UseProfileOrDefault(ProfileDescription.DefaultExecutablePath, workerDescription.DefaultExecutablePath);
79-
workerDescription.DefaultWorkerPath = UseProfileOrDefault(ProfileDescription.DefaultWorkerPath, workerDescription.DefaultWorkerPath);
80-
workerDescription.Extensions = UseProfileOrDefault(ProfileDescription.Extensions, workerDescription.Extensions) as List<string>;
81-
workerDescription.Language = UseProfileOrDefault(ProfileDescription.Language, workerDescription.Language);
82-
workerDescription.WorkerDirectory = UseProfileOrDefault(ProfileDescription.WorkerDirectory, workerDescription.WorkerDirectory);
83-
return workerDescription;
77+
RpcWorkerDescription updatedDescription = new ();
78+
updatedDescription.Arguments = UseProfileOrDefault(ProfileDescription.Arguments, defaultWorkerDescription.Arguments);
79+
updatedDescription.DefaultExecutablePath = UseProfileOrDefault(ProfileDescription.DefaultExecutablePath, defaultWorkerDescription.DefaultExecutablePath);
80+
updatedDescription.DefaultWorkerPath = UseProfileOrDefault(ProfileDescription.DefaultWorkerPath, defaultWorkerDescription.DefaultWorkerPath);
81+
updatedDescription.Extensions = UseProfileOrDefault(ProfileDescription.Extensions, defaultWorkerDescription.Extensions) as List<string>;
82+
updatedDescription.Language = UseProfileOrDefault(ProfileDescription.Language, defaultWorkerDescription.Language);
83+
updatedDescription.WorkerDirectory = UseProfileOrDefault(ProfileDescription.WorkerDirectory, defaultWorkerDescription.WorkerDirectory);
84+
return updatedDescription;
8485
}
8586

8687
private string UseProfileOrDefault(string profileParameter, string defaultParameter)

src/WebJobs.Script/Workers/Profiles/WorkerProfileManager.cs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
2-
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
2+
// Licensed under the MIT License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
55
using System.Collections.Generic;
@@ -15,16 +15,22 @@ namespace Microsoft.Azure.WebJobs.Script.Workers
1515
internal class WorkerProfileManager : IWorkerProfileManager
1616
{
1717
private readonly ILogger _logger;
18+
private readonly IEnvironment _environment;
1819
private readonly IEnumerable<IWorkerProfileConditionProvider> _conditionProviders;
20+
21+
private string _activeProfile = string.Empty;
1922
private Dictionary<string, List<WorkerDescriptionProfile>> _profiles;
20-
private string _activeProfile;
2123

22-
public WorkerProfileManager(ILogger logger, IEnumerable<IWorkerProfileConditionProvider> conditionProviders)
24+
public WorkerProfileManager(ILogger<WorkerProfileManager> logger, IEnvironment environment)
2325
{
26+
_environment = environment ?? throw new ArgumentNullException(nameof(environment));
2427
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
25-
_conditionProviders = conditionProviders ?? throw new ArgumentNullException(nameof(conditionProviders));
28+
2629
_profiles = new Dictionary<string, List<WorkerDescriptionProfile>>();
27-
_activeProfile = string.Empty;
30+
_conditionProviders = new List<IWorkerProfileConditionProvider>
31+
{
32+
new WorkerProfileConditionProvider(_logger, _environment)
33+
};
2834
}
2935

3036
/// <inheritdoc />
@@ -59,9 +65,11 @@ public void LoadWorkerDescriptionFromProfiles(RpcWorkerDescription defaultWorker
5965
_logger?.LogInformation($"Worker initialized with profile - {profile.Name}, Profile ID {profile.ProfileId} from worker config.");
6066
_activeProfile = profile.ProfileId;
6167
workerDescription = profile.ApplyProfile(defaultWorkerDescription);
62-
return;
6368
}
64-
workerDescription = defaultWorkerDescription;
69+
else
70+
{
71+
workerDescription = defaultWorkerDescription;
72+
}
6573
}
6674

6775
/// <inheritdoc />
@@ -87,7 +95,7 @@ public bool IsCorrectProfileLoaded(string workerRuntime)
8795
var profileId = string.Empty;
8896
if (GetEvaluatedProfile(workerRuntime, out WorkerDescriptionProfile profile))
8997
{
90-
profileId = profile.ProfileId;
98+
profileId = profile.ProfileId;
9199
}
92100
return _activeProfile.Equals(profileId);
93101
}

src/WebJobs.Script/Workers/Rpc/Configuration/LanguageWorkerOptionsSetup.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Collections.Generic;
66
using Microsoft.Azure.WebJobs.Script.Diagnostics;
7+
using Microsoft.Azure.WebJobs.Script.Workers.Profiles;
78
using Microsoft.Extensions.Configuration;
89
using Microsoft.Extensions.Logging;
910
using Microsoft.Extensions.Options;
@@ -16,11 +17,13 @@ internal class LanguageWorkerOptionsSetup : IConfigureOptions<LanguageWorkerOpti
1617
private readonly ILogger _logger;
1718
private readonly IEnvironment _environment;
1819
private readonly IMetricsLogger _metricsLogger;
20+
private readonly IWorkerProfileManager _workerProfileManager;
1921

2022
public LanguageWorkerOptionsSetup(IConfiguration configuration,
2123
ILoggerFactory loggerFactory,
2224
IEnvironment environment,
23-
IMetricsLogger metricsLogger)
25+
IMetricsLogger metricsLogger,
26+
IWorkerProfileManager workerProfileManager)
2427
{
2528
if (loggerFactory is null)
2629
{
@@ -30,6 +33,7 @@ public LanguageWorkerOptionsSetup(IConfiguration configuration,
3033
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
3134
_environment = environment ?? throw new ArgumentNullException(nameof(environment));
3235
_metricsLogger = metricsLogger ?? throw new ArgumentNullException(nameof(metricsLogger));
36+
_workerProfileManager = workerProfileManager ?? throw new ArgumentNullException(nameof(workerProfileManager));
3337

3438
_logger = loggerFactory.CreateLogger("Host.LanguageWorkerConfig");
3539
}
@@ -44,7 +48,7 @@ public void Configure(LanguageWorkerOptions options)
4448
return;
4549
}
4650

47-
var configFactory = new RpcWorkerConfigFactory(_configuration, _logger, SystemRuntimeInformation.Instance, _environment, _metricsLogger);
51+
var configFactory = new RpcWorkerConfigFactory(_configuration, _logger, SystemRuntimeInformation.Instance, _environment, _metricsLogger, _workerProfileManager);
4852
options.WorkerConfigs = configFactory.GetConfigs();
4953
}
5054
}

src/WebJobs.Script/Workers/Rpc/Configuration/RpcWorkerConfigFactory.cs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
using Microsoft.Azure.WebJobs.Script.Workers.Profiles;
1111
using Microsoft.Extensions.Configuration;
1212
using Microsoft.Extensions.Logging;
13-
using Newtonsoft.Json;
1413
using Newtonsoft.Json.Linq;
1514

1615
namespace Microsoft.Azure.WebJobs.Script.Workers.Rpc
@@ -32,22 +31,17 @@ public RpcWorkerConfigFactory(IConfiguration config,
3231
ILogger logger,
3332
ISystemRuntimeInformation systemRuntimeInfo,
3433
IEnvironment environment,
35-
IMetricsLogger metricsLogger)
34+
IMetricsLogger metricsLogger,
35+
IWorkerProfileManager workerProfileManager)
3636
{
3737
_config = config ?? throw new ArgumentNullException(nameof(config));
3838
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
3939
_systemRuntimeInformation = systemRuntimeInfo ?? throw new ArgumentNullException(nameof(systemRuntimeInfo));
4040
_environment = environment ?? throw new ArgumentNullException(nameof(environment));
41-
_metricsLogger = metricsLogger;
41+
_metricsLogger = metricsLogger ?? throw new ArgumentNullException(nameof(metricsLogger));
42+
_profileManager = workerProfileManager ?? throw new ArgumentNullException(nameof(workerProfileManager));
4243
_workerRuntime = _environment.GetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeSettingName);
4344

44-
var conditionProviders = new List<IWorkerProfileConditionProvider>
45-
{
46-
new WorkerProfileConditionProvider(_logger, _environment)
47-
};
48-
49-
_profileManager = new WorkerProfileManager(_logger, conditionProviders);
50-
5145
WorkersDirPath = GetDefaultWorkersDirectory(Directory.Exists);
5246
var workersDirectorySection = _config.GetSection($"{RpcWorkerConstants.LanguageWorkersSectionName}:{WorkerConstants.WorkersDirectorySectionName}");
5347

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

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public class WebHostRpcWorkerChannelManager : IWebHostRpcWorkerChannelManager
2121
private readonly ILogger _logger = null;
2222
private readonly TimeSpan workerInitTimeout = TimeSpan.FromSeconds(30);
2323
private readonly IOptionsMonitor<ScriptApplicationHostOptions> _applicationHostOptions = null;
24-
private readonly IOptionsMonitor<LanguageWorkerOptions> _lanuageworkerOptions = null;
24+
private readonly IOptionsMonitor<LanguageWorkerOptions> _languageWorkerOptions = null;
2525
private readonly IScriptEventManager _eventManager = null;
2626
private readonly IEnvironment _environment;
2727
private readonly ILoggerFactory _loggerFactory = null;
@@ -40,22 +40,20 @@ public WebHostRpcWorkerChannelManager(IScriptEventManager eventManager,
4040
IRpcWorkerChannelFactory rpcWorkerChannelFactory,
4141
IOptionsMonitor<ScriptApplicationHostOptions> applicationHostOptions,
4242
IMetricsLogger metricsLogger, IOptionsMonitor<LanguageWorkerOptions> languageWorkerOptions,
43-
IConfiguration config)
43+
IConfiguration config,
44+
IWorkerProfileManager workerProfileManager)
4445
{
4546
_environment = environment ?? throw new ArgumentNullException(nameof(environment));
47+
_config = config ?? throw new ArgumentNullException(nameof(config));
48+
_profileManager = workerProfileManager ?? throw new ArgumentNullException(nameof(workerProfileManager));
4649
_eventManager = eventManager;
4750
_loggerFactory = loggerFactory;
4851
_metricsLogger = metricsLogger;
4952
_rpcWorkerChannelFactory = rpcWorkerChannelFactory;
5053
_logger = loggerFactory.CreateLogger<WebHostRpcWorkerChannelManager>();
5154
_applicationHostOptions = applicationHostOptions;
52-
_lanuageworkerOptions = languageWorkerOptions;
53-
_config = config ?? throw new ArgumentNullException(nameof(config));
54-
var conditionProviders = new List<IWorkerProfileConditionProvider>
55-
{
56-
new WorkerProfileConditionProvider(_logger, _environment)
57-
};
58-
_profileManager = new WorkerProfileManager(_logger, conditionProviders);
55+
_languageWorkerOptions = languageWorkerOptions;
56+
5957
_shutdownStandbyWorkerChannels = ScheduleShutdownStandbyChannels;
6058
_shutdownStandbyWorkerChannels = _shutdownStandbyWorkerChannels.Debounce(milliseconds: 5000);
6159
}
@@ -73,7 +71,7 @@ internal async Task<IRpcWorkerChannel> InitializeLanguageWorkerChannel(string ru
7371
_logger.LogDebug("Creating language worker channel for runtime:{runtime}", runtime);
7472
try
7573
{
76-
rpcWorkerChannel = _rpcWorkerChannelFactory.Create(scriptRootPath, runtime, _metricsLogger, 0, _lanuageworkerOptions.CurrentValue.WorkerConfigs);
74+
rpcWorkerChannel = _rpcWorkerChannelFactory.Create(scriptRootPath, runtime, _metricsLogger, 0, _languageWorkerOptions.CurrentValue.WorkerConfigs);
7775
AddOrUpdateWorkerChannels(runtime, rpcWorkerChannel);
7876
await rpcWorkerChannel.StartWorkerProcessAsync().ContinueWith(processStartTask =>
7977
{
@@ -159,9 +157,9 @@ private bool UsePlaceholderChannel(string workerRuntime)
159157
// Special case: node and PowerShell apps must be read-only to use the placeholder mode channel
160158
// Also cannot use placeholder worker that is targeting ~3 but has backwards compatibility with V2 enabled
161159
// TODO: Remove special casing when resolving https://github.com/Azure/azure-functions-host/issues/4534
162-
if (workerRuntime.ToLowerInvariant() is RpcWorkerConstants.NodeLanguageWorkerName
163-
or RpcWorkerConstants.PowerShellLanguageWorkerName
164-
or RpcWorkerConstants.PythonLanguageWorkerName)
160+
if (string.Equals(workerRuntime, RpcWorkerConstants.NodeLanguageWorkerName, StringComparison.OrdinalIgnoreCase)
161+
|| string.Equals(workerRuntime, RpcWorkerConstants.PowerShellLanguageWorkerName, StringComparison.OrdinalIgnoreCase)
162+
|| string.Equals(workerRuntime, RpcWorkerConstants.PythonLanguageWorkerName, StringComparison.OrdinalIgnoreCase))
165163
{
166164
// Use if readonly and not v2 compatible on ~3 extension
167165
return _applicationHostOptions.CurrentValue.IsFileSystemReadOnly && !_environment.IsV2CompatibleOnV3Extension();

test/WebJobs.Script.Tests/Configuration/LanguageWorkerOptionsSetupTests.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33

44
using System;
55
using Microsoft.Azure.WebJobs.Script.Workers;
6+
using Microsoft.Azure.WebJobs.Script.Workers.Profiles;
67
using Microsoft.Azure.WebJobs.Script.Workers.Rpc;
78
using Microsoft.Extensions.Configuration;
89
using Microsoft.Extensions.Logging.Abstractions;
10+
using Moq;
911
using Xunit;
1012

1113
namespace Microsoft.Azure.WebJobs.Script.Tests.Configuration
@@ -21,17 +23,22 @@ public void LanguageWorkerOptions_Expected_ListOfConfigs(string workerRuntime)
2123
{
2224
var runtimeInfo = new TestSystemRuntimeInformation();
2325
var testEnvironment = new TestEnvironment();
26+
var testMetricLogger = new TestMetricsLogger();
2427
var configurationBuilder = new ConfigurationBuilder()
2528
.Add(new ScriptEnvironmentVariablesConfigurationSource());
26-
2729
var configuration = configurationBuilder.Build();
30+
var testProfileManager = new Mock<IWorkerProfileManager>();
31+
2832
if (!string.IsNullOrEmpty(workerRuntime))
2933
{
3034
testEnvironment.SetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeSettingName, workerRuntime);
3135
}
32-
LanguageWorkerOptionsSetup setup = new LanguageWorkerOptionsSetup(configuration, NullLoggerFactory.Instance, testEnvironment, new TestMetricsLogger());
36+
37+
LanguageWorkerOptionsSetup setup = new LanguageWorkerOptionsSetup(configuration, NullLoggerFactory.Instance, testEnvironment, testMetricLogger, testProfileManager.Object);
3338
LanguageWorkerOptions options = new LanguageWorkerOptions();
39+
3440
setup.Configure(options);
41+
3542
if (string.IsNullOrEmpty(workerRuntime))
3643
{
3744
Assert.Equal(4, options.WorkerConfigs.Count);

test/WebJobs.Script.Tests/Workers/Profiles/EnvironmentConditionTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
2-
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
33

44
using System;
55
using System.ComponentModel.DataAnnotations;

test/WebJobs.Script.Tests/Workers/Profiles/FalseConditionTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
2-
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
33

44
using Microsoft.Azure.WebJobs.Script.Workers.Profiles;
55
using Xunit;

test/WebJobs.Script.Tests/Workers/Profiles/HostPropertyConditionTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
2-
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
33

44
using System.ComponentModel.DataAnnotations;
55
using Microsoft.Azure.WebJobs.Script.Workers;

0 commit comments

Comments
 (0)