Skip to content

Commit 530e812

Browse files
committed
Consolidating use of IOptions and IOptionsMonitor in used at specialization to avoid duplicate setup runs
1 parent 1a62cef commit 530e812

File tree

12 files changed

+50
-48
lines changed

12 files changed

+50
-48
lines changed

src/WebJobs.Script/DependencyInjection/ScriptStartupTypeLocator.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ public class ScriptStartupTypeLocator : IWebJobsStartupTypeLocator
3737
private readonly IFunctionMetadataManager _functionMetadataManager;
3838
private readonly IMetricsLogger _metricsLogger;
3939
private readonly Lazy<IEnumerable<Type>> _startupTypes;
40-
private readonly IOptions<LanguageWorkerOptions> _languageWorkerOptions;
40+
private readonly IOptionsMonitor<LanguageWorkerOptions> _languageWorkerOptions;
4141

4242
private static readonly ExtensionRequirementsInfo _extensionRequirements = DependencyHelper.GetExtensionRequirements();
4343
private static string[] _builtinExtensionAssemblies = GetBuiltinExtensionAssemblies();
4444

4545
public ScriptStartupTypeLocator(string rootScriptPath, ILogger<ScriptStartupTypeLocator> logger, IExtensionBundleManager extensionBundleManager,
46-
IFunctionMetadataManager functionMetadataManager, IMetricsLogger metricsLogger, IOptions<LanguageWorkerOptions> languageWorkerOptions)
46+
IFunctionMetadataManager functionMetadataManager, IMetricsLogger metricsLogger, IOptionsMonitor<LanguageWorkerOptions> languageWorkerOptions)
4747
{
4848
_rootScriptPath = rootScriptPath ?? throw new ArgumentNullException(nameof(rootScriptPath));
4949
_extensionBundleManager = extensionBundleManager ?? throw new ArgumentNullException(nameof(extensionBundleManager));
@@ -85,7 +85,7 @@ public async Task<IEnumerable<Type>> GetExtensionsStartupTypesAsync()
8585
// if workerIndexing
8686
// Function.json (httpTrigger, blobTrigger, blobTrigger) -> httpTrigger, blobTrigger
8787
// dotnet app precompiled -> Do not use bundles
88-
var workerConfigs = _languageWorkerOptions.Value.WorkerConfigs;
88+
var workerConfigs = _languageWorkerOptions.CurrentValue.WorkerConfigs;
8989
if (bundleConfigured && !Utility.CanWorkerIndex(workerConfigs, SystemEnvironment.Instance))
9090
{
9191
ExtensionBundleDetails bundleDetails = await _extensionBundleManager.GetExtensionBundleDetails();

src/WebJobs.Script/Host/FunctionMetadataManager.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ public class FunctionMetadataManager : IFunctionMetadataManager
3030
private bool _servicesReset = false;
3131
private ILogger _logger;
3232
private IOptions<ScriptJobHostOptions> _scriptOptions;
33-
private IOptions<LanguageWorkerOptions> _languageWorkerOptions;
33+
private IOptionsMonitor<LanguageWorkerOptions> _languageWorkerOptions;
3434
private ImmutableArray<FunctionMetadata> _functionMetadataArray;
3535
private Dictionary<string, ICollection<string>> _functionErrors = new Dictionary<string, ICollection<string>>();
3636
private ConcurrentDictionary<string, FunctionMetadata> _functionMetadataMap = new ConcurrentDictionary<string, FunctionMetadata>(StringComparer.OrdinalIgnoreCase);
3737

3838
public FunctionMetadataManager(IOptions<ScriptJobHostOptions> scriptOptions, IFunctionMetadataProvider functionMetadataProvider,
3939
IOptions<HttpWorkerOptions> httpWorkerOptions, IScriptHostManager scriptHostManager, ILoggerFactory loggerFactory,
40-
IOptions<LanguageWorkerOptions> languageWorkerOptions, IEnvironment environment)
40+
IOptionsMonitor<LanguageWorkerOptions> languageWorkerOptions, IEnvironment environment)
4141
{
4242
_scriptOptions = scriptOptions;
4343
_languageWorkerOptions = languageWorkerOptions;
@@ -111,7 +111,7 @@ private void InitializeServices()
111111

112112
_isHttpWorker = _serviceProvider.GetService<IOptions<HttpWorkerOptions>>()?.Value?.Description != null;
113113
_scriptOptions = _serviceProvider.GetService<IOptions<ScriptJobHostOptions>>();
114-
_languageWorkerOptions = _serviceProvider.GetService<IOptions<LanguageWorkerOptions>>();
114+
_languageWorkerOptions = _serviceProvider.GetService<IOptionsMonitor<LanguageWorkerOptions>>();
115115

116116
// Resetting the logger switches the logger scope to Script Host level,
117117
// also making the logs available to Application Insights
@@ -130,7 +130,7 @@ internal ImmutableArray<FunctionMetadata> LoadFunctionMetadata(bool forceRefresh
130130
_logger.FunctionMetadataManagerLoadingFunctionsMetadata();
131131

132132
ImmutableArray<FunctionMetadata> immutableFunctionMetadata;
133-
var workerConfigs = _languageWorkerOptions.Value.WorkerConfigs;
133+
var workerConfigs = _languageWorkerOptions.CurrentValue.WorkerConfigs;
134134

135135
IFunctionMetadataProvider metadataProvider = new AggregateFunctionMetadataProvider(_loggerFactory.CreateLogger<AggregateFunctionMetadataProvider>(), dispatcher, _functionMetadataProvider, _scriptOptions);
136136

src/WebJobs.Script/Host/ScriptHost.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public class ScriptHost : JobHost, IScriptJobHost
6666
private readonly string _instanceId;
6767
private readonly IEnvironment _environment;
6868
private readonly IFunctionDataCache _functionDataCache;
69-
private readonly IOptions<LanguageWorkerOptions> _languageWorkerOptions;
69+
private readonly IOptionsMonitor<LanguageWorkerOptions> _languageWorkerOptions;
7070
private static readonly int _processId = Process.GetCurrentProcess().Id;
7171

7272
private ValueStopwatch _stopwatch;
@@ -106,7 +106,7 @@ public ScriptHost(IOptions<JobHostOptions> options,
106106
IApplicationLifetime applicationLifetime,
107107
IExtensionBundleManager extensionBundleManager,
108108
IFunctionDataCache functionDataCache,
109-
IOptions<LanguageWorkerOptions> languageWorkerOptions,
109+
IOptionsMonitor<LanguageWorkerOptions> languageWorkerOptions,
110110
ScriptSettingsManager settingsManager = null)
111111
: base(options, jobHostContextFactory)
112112
{
@@ -280,7 +280,7 @@ public async Task InitializeAsync(CancellationToken cancellationToken = default)
280280
_workerRuntime = _workerRuntime ?? _environment.GetEnvironmentVariable(EnvironmentSettingNames.FunctionWorkerRuntime);
281281

282282
// get worker config information and check to see if worker should index or not
283-
var workerConfigs = _languageWorkerOptions.Value.WorkerConfigs;
283+
var workerConfigs = _languageWorkerOptions.CurrentValue.WorkerConfigs;
284284

285285
bool workerIndexing = Utility.CanWorkerIndex(workerConfigs, _environment);
286286

@@ -548,8 +548,10 @@ private void AddFunctionDescriptors(IEnumerable<FunctionMetadata> functionMetada
548548
{
549549
_logger.AddingDescriptorProviderForLanguage("All (Multi Language)");
550550

551-
_descriptorProviders.Add(new MultiLanguageFunctionDescriptorProvider(this, _languageWorkerOptions.Value.WorkerConfigs, ScriptOptions, _bindingProviders,
552-
_functionDispatcher, _loggerFactory, _applicationLifetime, _languageWorkerOptions.Value.WorkerConfigs.Max(wc => wc.CountOptions.InitializationTimeout)));
551+
var workerOptions = _languageWorkerOptions.CurrentValue;
552+
553+
_descriptorProviders.Add(new MultiLanguageFunctionDescriptorProvider(this, workerOptions.WorkerConfigs, ScriptOptions, _bindingProviders,
554+
_functionDispatcher, _loggerFactory, _applicationLifetime, workerOptions.WorkerConfigs.Max(wc => wc.CountOptions.InitializationTimeout)));
553555
}
554556
else if (_isHttpWorker)
555557
{
@@ -565,7 +567,7 @@ private void AddFunctionDescriptors(IEnumerable<FunctionMetadata> functionMetada
565567
{
566568
_logger.AddingDescriptorProviderForLanguage(_workerRuntime);
567569

568-
var workerConfig = _languageWorkerOptions.Value.WorkerConfigs?.FirstOrDefault(c => c.Description.Language.Equals(_workerRuntime, StringComparison.OrdinalIgnoreCase));
570+
var workerConfig = _languageWorkerOptions.CurrentValue.WorkerConfigs?.FirstOrDefault(c => c.Description.Language.Equals(_workerRuntime, StringComparison.OrdinalIgnoreCase));
569571

570572
// If there's no worker config, use the default (for legacy behavior; mostly for tests).
571573
TimeSpan initializationTimeout = workerConfig?.CountOptions?.InitializationTimeout ?? WorkerProcessCountOptions.DefaultInitializationTimeout;

src/WebJobs.Script/ScriptHostBuilderExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public static IHostBuilder AddScriptHost(this IHostBuilder builder,
112112
var extensionBundleOptions = GetExtensionBundleOptions(config);
113113
var bundleManager = new ExtensionBundleManager(extensionBundleOptions, SystemEnvironment.Instance, loggerFactory);
114114
var metadataServiceManager = applicationOptions.RootServiceProvider.GetService<IFunctionMetadataManager>();
115-
var languageWorkerOptions = applicationOptions.RootServiceProvider.GetService<IOptions<LanguageWorkerOptions>>();
115+
var languageWorkerOptions = applicationOptions.RootServiceProvider.GetService<IOptionsMonitor<LanguageWorkerOptions>>();
116116

117117
var locator = new ScriptStartupTypeLocator(applicationOptions.ScriptPath, loggerFactory.CreateLogger<ScriptStartupTypeLocator>(), bundleManager, metadataServiceManager, metricsLogger, languageWorkerOptions);
118118

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,9 @@ public async Task StandbyModeE2E_LinuxContainer()
122122
Assert.Equal(1, logLines.Count(p => p.Contains("Validating host assignment context")));
123123
Assert.Equal(1, logLines.Count(p => p.Contains("Starting Assignment")));
124124
Assert.Equal(1, logLines.Count(p => p.Contains("Applying 3 app setting(s)")));
125-
Assert.Equal(2, logLines.Count(p => p.Contains($"Skipping WorkerConfig for language:python")));
126-
Assert.Equal(2, logLines.Count(p => p.Contains($"Skipping WorkerConfig for language:powershell")));
127-
Assert.Equal(2, logLines.Count(p => p.Contains($"Skipping WorkerConfig for language:java")));
125+
Assert.Equal(1, logLines.Count(p => p.Contains($"Skipping WorkerConfig for language:python")));
126+
Assert.Equal(1, logLines.Count(p => p.Contains($"Skipping WorkerConfig for language:powershell")));
127+
Assert.Equal(1, logLines.Count(p => p.Contains($"Skipping WorkerConfig for language:java")));
128128
Assert.Equal(1, logLines.Count(p => p.Contains($"Extracting files to '{_expectedScriptPath}'")));
129129
Assert.Equal(1, logLines.Count(p => p.Contains("Zip extraction complete")));
130130
Assert.Equal(1, logLines.Count(p => p.Contains("Triggering specialization")));

test/WebJobs.Script.Tests.Integration/Management/FunctionsSyncManagerTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ public FunctionsSyncManagerTests()
139139
_hostNameProvider = new HostNameProvider(_mockEnvironment.Object);
140140

141141
var functionMetadataProvider = new HostFunctionMetadataProvider(optionsMonitor, NullLogger<HostFunctionMetadataProvider>.Instance, new TestMetricsLogger());
142-
var functionMetadataManager = TestFunctionMetadataManager.GetFunctionMetadataManager(new OptionsWrapper<ScriptJobHostOptions>(jobHostOptions), functionMetadataProvider, null, new OptionsWrapper<HttpWorkerOptions>(new HttpWorkerOptions()), loggerFactory, new OptionsWrapper<LanguageWorkerOptions>(CreateLanguageWorkerConfigSettings()));
142+
var functionMetadataManager = TestFunctionMetadataManager.GetFunctionMetadataManager(new OptionsWrapper<ScriptJobHostOptions>(jobHostOptions), functionMetadataProvider, null, new OptionsWrapper<HttpWorkerOptions>(new HttpWorkerOptions()), loggerFactory, new TestOptionsMonitor<LanguageWorkerOptions>(CreateLanguageWorkerConfigSettings()));
143143

144144
_scriptHostManager = new TestScriptHostService(configuration);
145145
var azureBlobStorageProvider = TestHelpers.GetAzureBlobStorageProvider(configuration, scriptHostManager: _scriptHostManager);

test/WebJobs.Script.Tests.Integration/TestFunctionHost.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ private FunctionMetadataManager GetMetadataManager(IOptionsMonitor<ScriptApplica
488488

489489
var metadataProvider = new HostFunctionMetadataProvider(optionsMonitor, NullLogger<HostFunctionMetadataProvider>.Instance, new TestMetricsLogger());
490490
var metadataManager = new FunctionMetadataManager(managerServiceProvider.GetService<IOptions<ScriptJobHostOptions>>(), metadataProvider,
491-
managerServiceProvider.GetService<IOptions<HttpWorkerOptions>>(), manager, factory, new OptionsWrapper<LanguageWorkerOptions>(workerOptions), environment);
491+
managerServiceProvider.GetService<IOptions<HttpWorkerOptions>>(), manager, factory, new TestOptionsMonitor<LanguageWorkerOptions>(workerOptions), environment);
492492

493493
return metadataManager;
494494
}

test/WebJobs.Script.Tests.Shared/TestFunctionMetadataManager.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,27 @@ namespace Microsoft.Azure.WebJobs.Script.Tests
1818
public static class TestFunctionMetadataManager
1919
{
2020
public static FunctionMetadataManager GetFunctionMetadataManager(IOptions<ScriptJobHostOptions> jobHostOptions, IFunctionMetadataProvider functionMetadataProvider,
21-
IOptions<HttpWorkerOptions> httpOptions, ILoggerFactory loggerFactory, IOptions<LanguageWorkerOptions> languageWorkerOptions)
21+
IOptions<HttpWorkerOptions> httpOptions, ILoggerFactory loggerFactory, IOptionsMonitor<LanguageWorkerOptions> languageWorkerOptions)
2222
{
2323
return GetFunctionMetadataManager(jobHostOptions, functionMetadataProvider, new List<IFunctionProvider>(), httpOptions, loggerFactory, languageWorkerOptions);
2424
}
2525

2626
public static FunctionMetadataManager GetFunctionMetadataManager(IOptions<ScriptJobHostOptions> jobHostOptions,
2727
IFunctionMetadataProvider functionMetadataProvider, IList<IFunctionProvider> functionProviders, IOptions<HttpWorkerOptions> httpOptions,
28-
ILoggerFactory loggerFactory, IOptions<LanguageWorkerOptions> languageWorkerOptions)
28+
ILoggerFactory loggerFactory, IOptionsMonitor<LanguageWorkerOptions> languageWorkerOptions)
2929
{
3030
var managerMock = new Mock<IScriptHostManager>();
3131

3232
return GetFunctionMetadataManager(jobHostOptions, managerMock, functionMetadataProvider, functionProviders, httpOptions, loggerFactory, languageWorkerOptions);
3333
}
3434

3535
public static FunctionMetadataManager GetFunctionMetadataManager(IOptions<ScriptJobHostOptions> jobHostOptions, Mock<IScriptHostManager> managerMock,
36-
IFunctionMetadataProvider functionMetadataProvider, IList<IFunctionProvider> functionProviders, IOptions<HttpWorkerOptions> httpOptions, ILoggerFactory loggerFactory, IOptions<LanguageWorkerOptions> languageWorkerOptions)
36+
IFunctionMetadataProvider functionMetadataProvider, IList<IFunctionProvider> functionProviders, IOptions<HttpWorkerOptions> httpOptions, ILoggerFactory loggerFactory, IOptionsMonitor<LanguageWorkerOptions> languageWorkerOptions)
3737
{
3838
managerMock.As<IServiceProvider>().Setup(m => m.GetService(typeof(IEnumerable<IFunctionProvider>))).Returns(functionProviders);
3939
managerMock.As<IServiceProvider>().Setup(m => m.GetService(typeof(IOptions<ScriptJobHostOptions>))).Returns(jobHostOptions);
4040
managerMock.As<IServiceProvider>().Setup(m => m.GetService(typeof(IOptions<HttpWorkerOptions>))).Returns(httpOptions);
41-
managerMock.As<IServiceProvider>().Setup(m => m.GetService(typeof(IOptions<LanguageWorkerOptions>))).Returns(languageWorkerOptions);
41+
managerMock.As<IServiceProvider>().Setup(m => m.GetService(typeof(IOptionsMonitor<LanguageWorkerOptions>))).Returns(languageWorkerOptions);
4242
managerMock.As<IServiceProvider>().Setup(m => m.GetService(typeof(ILoggerFactory))).Returns(loggerFactory);
4343

4444
var options = new ScriptApplicationHostOptions()

test/WebJobs.Script.Tests.Shared/TestHostBuilderExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ private static IServiceCollection AddFunctionMetadataManager(this IServiceCollec
100100
var optionsMonitor = new OptionsMonitor<ScriptApplicationHostOptions>(factory, changeTokens, factory);
101101

102102
var metadataProvider = new HostFunctionMetadataProvider(optionsMonitor, NullLogger<HostFunctionMetadataProvider>.Instance, metricsLogger);
103-
var metadataManager = TestFunctionMetadataManager.GetFunctionMetadataManager(new OptionsWrapper<ScriptJobHostOptions>(new ScriptJobHostOptions()), metadataProvider, new List<IFunctionProvider>(), new OptionsWrapper<HttpWorkerOptions>(new HttpWorkerOptions()), new NullLoggerFactory(), new OptionsWrapper<LanguageWorkerOptions>(TestHelpers.GetTestLanguageWorkerOptions()));
103+
var metadataManager = TestFunctionMetadataManager.GetFunctionMetadataManager(new OptionsWrapper<ScriptJobHostOptions>(new ScriptJobHostOptions()), metadataProvider, new List<IFunctionProvider>(), new OptionsWrapper<HttpWorkerOptions>(new HttpWorkerOptions()), new NullLoggerFactory(), new TestOptionsMonitor<LanguageWorkerOptions>(TestHelpers.GetTestLanguageWorkerOptions()));
104104
services.AddSingleton<IFunctionMetadataManager>(metadataManager);
105105
services.AddSingleton<IFunctionMetadataProvider>(metadataProvider);
106106

0 commit comments

Comments
 (0)