Skip to content

Commit f4e9ce6

Browse files
authored
[v3.x] Redesign for Functions Hosting config (#8974)
1 parent 9178fe6 commit f4e9ce6

25 files changed

+665
-359
lines changed

src/WebJobs.Script.Grpc/Channel/GrpcWorkerChannel.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using System.Threading.Tasks;
1515
using System.Threading.Tasks.Dataflow;
1616
using Microsoft.Azure.WebJobs.Logging;
17+
using Microsoft.Azure.WebJobs.Script.Config;
1718
using Microsoft.Azure.WebJobs.Script.Description;
1819
using Microsoft.Azure.WebJobs.Script.Diagnostics;
1920
using Microsoft.Azure.WebJobs.Script.Eventing;
@@ -44,6 +45,7 @@ internal class GrpcWorkerChannel : IRpcWorkerChannel, IDisposable
4445
private readonly ISharedMemoryManager _sharedMemoryManager;
4546
private readonly List<TimeSpan> _workerStatusLatencyHistory = new List<TimeSpan>();
4647
private readonly IOptions<WorkerConcurrencyOptions> _workerConcurrencyOptions;
48+
private readonly IOptions<FunctionsHostingConfigOptions> _hostingConfigOptions;
4749

4850
private IDisposable _functionLoadRequestResponseEvent;
4951
private bool _disposed;
@@ -87,7 +89,8 @@ internal GrpcWorkerChannel(
8789
IOptionsMonitor<ScriptApplicationHostOptions> applicationHostOptions,
8890
ISharedMemoryManager sharedMemoryManager,
8991
IFunctionDataCache functionDataCache,
90-
IOptions<WorkerConcurrencyOptions> workerConcurrencyOptions)
92+
IOptions<WorkerConcurrencyOptions> workerConcurrencyOptions,
93+
IOptions<FunctionsHostingConfigOptions> hostingConfigOptions)
9194
{
9295
_workerId = workerId;
9396
_eventManager = eventManager;
@@ -100,6 +103,7 @@ internal GrpcWorkerChannel(
100103
_applicationHostOptions = applicationHostOptions;
101104
_sharedMemoryManager = sharedMemoryManager;
102105
_workerConcurrencyOptions = workerConcurrencyOptions;
106+
_hostingConfigOptions = hostingConfigOptions;
103107

104108
_workerCapabilities = new GrpcCapabilities(_workerChannelLogger);
105109

@@ -391,6 +395,11 @@ public Task SendFunctionEnvironmentReloadRequest()
391395

392396
internal FunctionEnvironmentReloadRequest GetFunctionEnvironmentReloadRequest(IDictionary processEnv)
393397
{
398+
foreach (var pair in _hostingConfigOptions.Value.Features)
399+
{
400+
processEnv[pair.Key] = pair.Value;
401+
}
402+
394403
FunctionEnvironmentReloadRequest request = new FunctionEnvironmentReloadRequest();
395404
foreach (DictionaryEntry entry in processEnv)
396405
{

src/WebJobs.Script.Grpc/Channel/GrpcWorkerChannelFactory.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Collections.Generic;
66
using System.Linq;
77
using System.Reactive.Linq;
8+
using Microsoft.Azure.WebJobs.Script.Config;
89
using Microsoft.Azure.WebJobs.Script.Diagnostics;
910
using Microsoft.Azure.WebJobs.Script.Eventing;
1011
using Microsoft.Azure.WebJobs.Script.Workers;
@@ -25,9 +26,11 @@ public class GrpcWorkerChannelFactory : IRpcWorkerChannelFactory
2526
private readonly ISharedMemoryManager _sharedMemoryManager = null;
2627
private readonly IFunctionDataCache _functionDataCache = null;
2728
private readonly IOptions<WorkerConcurrencyOptions> _workerConcurrencyOptions;
29+
private readonly IOptions<FunctionsHostingConfigOptions> _hostingConfigOptions;
2830

2931
public GrpcWorkerChannelFactory(IScriptEventManager eventManager, IEnvironment environment, IRpcServer rpcServer, ILoggerFactory loggerFactory, IOptionsMonitor<LanguageWorkerOptions> languageWorkerOptions,
30-
IOptionsMonitor<ScriptApplicationHostOptions> applicationHostOptions, IRpcWorkerProcessFactory rpcWorkerProcessManager, ISharedMemoryManager sharedMemoryManager, IFunctionDataCache functionDataCache, IOptions<WorkerConcurrencyOptions> workerConcurrencyOptions)
32+
IOptionsMonitor<ScriptApplicationHostOptions> applicationHostOptions, IRpcWorkerProcessFactory rpcWorkerProcessManager, ISharedMemoryManager sharedMemoryManager, IFunctionDataCache functionDataCache,
33+
IOptions<WorkerConcurrencyOptions> workerConcurrencyOptions, IOptions<FunctionsHostingConfigOptions> hostingConfigOptions)
3134
{
3235
_eventManager = eventManager;
3336
_loggerFactory = loggerFactory;
@@ -37,6 +40,7 @@ public GrpcWorkerChannelFactory(IScriptEventManager eventManager, IEnvironment e
3740
_sharedMemoryManager = sharedMemoryManager;
3841
_functionDataCache = functionDataCache;
3942
_workerConcurrencyOptions = workerConcurrencyOptions;
43+
_hostingConfigOptions = hostingConfigOptions;
4044
}
4145

4246
public IRpcWorkerChannel Create(string scriptRootPath, string runtime, IMetricsLogger metricsLogger, int attemptCount, IEnumerable<RpcWorkerConfig> workerConfigs)
@@ -61,7 +65,8 @@ public IRpcWorkerChannel Create(string scriptRootPath, string runtime, IMetricsL
6165
_applicationHostOptions,
6266
_sharedMemoryManager,
6367
_functionDataCache,
64-
_workerConcurrencyOptions);
68+
_workerConcurrencyOptions,
69+
_hostingConfigOptions);
6570
}
6671
}
6772
}

src/WebJobs.Script.WebHost/Program.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Threading;
77
using Microsoft.AspNetCore.Builder;
88
using Microsoft.AspNetCore.Hosting;
9+
using Microsoft.Azure.WebJobs.Script.Config;
910
using Microsoft.Azure.WebJobs.Script.WebHost.Configuration;
1011
using Microsoft.Azure.WebJobs.Script.WebHost.DependencyInjection;
1112
using Microsoft.Azure.WebJobs.Script.WebHost.Diagnostics;
@@ -69,6 +70,7 @@ public static IWebHostBuilder CreateWebHostBuilder(string[] args = null)
6970
IsLinuxContainerEnvironment = SystemEnvironment.Instance.IsAnyLinuxConsumption(),
7071
IsLinuxAppServiceEnvironment = SystemEnvironment.Instance.IsLinuxAppService()
7172
});
73+
config.Add(new FunctionsHostingConfigSource(SystemEnvironment.Instance));
7274
})
7375
.ConfigureLogging((context, loggingBuilder) =>
7476
{

src/WebJobs.Script.WebHost/WebHostServiceCollectionExtensions.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

4+
using System;
45
using System.IO.Abstractions;
56
using System.Net.Http;
67
using System.Runtime.InteropServices;
@@ -186,6 +187,11 @@ public static void AddWebJobsScriptHost(this IServiceCollection services, IConfi
186187
services.ConfigureOptions<LanguageWorkerOptionsSetup>();
187188
services.ConfigureOptionsWithChangeTokenSource<AppServiceOptions, AppServiceOptionsSetup, SpecializationChangeTokenSource<AppServiceOptions>>();
188189
services.ConfigureOptionsWithChangeTokenSource<HttpBodyControlOptions, HttpBodyControlOptionsSetup, SpecializationChangeTokenSource<HttpBodyControlOptions>>();
190+
services.ConfigureOptions<FunctionsHostingConfigOptionsSetup>();
191+
if (configuration != null)
192+
{
193+
services.Configure<FunctionsHostingConfigOptions>(configuration.GetSection(ScriptConstants.FunctionsHostingConfigSectionName));
194+
}
189195

190196
services.TryAddSingleton<IDependencyValidator, DependencyValidator>();
191197
services.TryAddSingleton<IJobHostMiddlewarePipeline>(s => DefaultMiddlewarePipeline.Empty);

src/WebJobs.Script.WebHost/WebScriptHostBuilderExtension.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
using Microsoft.Extensions.DependencyInjection.Extensions;
2626
using Microsoft.Extensions.Hosting;
2727
using Microsoft.Extensions.Logging;
28+
using Microsoft.Extensions.Options;
2829

2930
namespace Microsoft.Azure.WebJobs.Script.WebHost
3031
{
@@ -143,6 +144,11 @@ public static IHostBuilder AddWebScriptHost(this IHostBuilder builder, IServiceP
143144
services.AddSingleton<IFileMonitoringService, FileMonitoringService>();
144145
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService, IFileMonitoringService>(p => p.GetService<IFileMonitoringService>()));
145146

147+
IOptions<FunctionsHostingConfigOptions> hostingConfigOptions = rootServiceProvider.GetService<IOptions<FunctionsHostingConfigOptions>>();
148+
IOptionsMonitor<FunctionsHostingConfigOptions> hostingConfigOptionsMonitor = rootServiceProvider.GetService<IOptionsMonitor<FunctionsHostingConfigOptions>>();
149+
services.AddSingleton(hostingConfigOptions);
150+
services.AddSingleton(hostingConfigOptionsMonitor);
151+
146152
ConfigureRegisteredBuilders(services, rootServiceProvider);
147153
});
148154

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System.Collections.Generic;
5+
using Microsoft.Azure.WebJobs.Script.Workers.Rpc;
6+
7+
namespace Microsoft.Azure.WebJobs.Script.Config
8+
{
9+
public class FunctionsHostingConfigOptions
10+
{
11+
private readonly Dictionary<string, string> _features;
12+
13+
public FunctionsHostingConfigOptions()
14+
{
15+
_features = new Dictionary<string, string>();
16+
}
17+
18+
/// <summary>
19+
/// Gets all features in the hosting configuration.
20+
/// </summary>
21+
public Dictionary<string, string> Features => _features;
22+
23+
/// <summary>
24+
/// Gets a value indicating whether worker concurency feature is enabled in the hosting config.
25+
/// </summary>
26+
public bool FunctionsWorkerDynamicConcurrencyEnabled
27+
{
28+
get
29+
{
30+
return GetFeature(RpcWorkerConstants.FunctionsWorkerDynamicConcurrencyEnabled) == "1";
31+
}
32+
}
33+
34+
/// <summary>
35+
/// Gets feature by name.
36+
/// </summary>
37+
/// <param name="name">Feature name.</param>
38+
/// <returns>String value from hostig configuration.</returns>
39+
public string GetFeature(string name)
40+
{
41+
if (_features.TryGetValue(name, out string value))
42+
{
43+
return value;
44+
}
45+
return null;
46+
}
47+
}
48+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
using Microsoft.Extensions.Configuration;
10+
using Microsoft.Extensions.Options;
11+
12+
namespace Microsoft.Azure.WebJobs.Script.Config
13+
{
14+
internal class FunctionsHostingConfigOptionsSetup : IConfigureOptions<FunctionsHostingConfigOptions>
15+
{
16+
private readonly IConfiguration _configuration;
17+
18+
public FunctionsHostingConfigOptionsSetup(IConfiguration configuration)
19+
{
20+
_configuration = configuration;
21+
}
22+
23+
public void Configure(FunctionsHostingConfigOptions options)
24+
{
25+
IConfigurationSection section = _configuration.GetSection(ScriptConstants.FunctionsHostingConfigSectionName);
26+
if (section != null)
27+
{
28+
foreach (var pair in section.GetChildren())
29+
{
30+
if (!string.IsNullOrEmpty(pair.Value))
31+
{
32+
options.Features[pair.Key] = pair.Value;
33+
}
34+
}
35+
}
36+
}
37+
}
38+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.IO;
7+
using System.Linq;
8+
using System.Security.Permissions;
9+
using Microsoft.Extensions.Configuration;
10+
11+
namespace Microsoft.Azure.WebJobs.Script.Config
12+
{
13+
/// <summary>
14+
/// A file-based hosting configuration <see cref="FileConfigurationProvider"/>.
15+
/// </summary>
16+
public class FunctionsHostingConfigProvider : FileConfigurationProvider
17+
{
18+
/// <summary>
19+
/// Initializes a new instance of the <see cref="FunctionsHostingConfigProvider"/> class.
20+
/// </summary>
21+
/// <param name="source">The source settings.</param>
22+
public FunctionsHostingConfigProvider(FunctionsHostingConfigSource source) : base(source) { }
23+
24+
/// <summary>
25+
/// Loads the hosting config data from a stream.
26+
/// </summary>
27+
/// <param name="stream">The stream to read.</param>
28+
public override void Load(Stream stream)
29+
{
30+
StreamReader reader = new StreamReader(stream);
31+
string text = reader.ReadToEnd();
32+
Data = Parse(text);
33+
}
34+
35+
private static Dictionary<string, string> Parse(string settings)
36+
{
37+
// Expected settings: "ENABLE_FEATUREX=1,A=B,TimeOut=123"
38+
return string.IsNullOrEmpty(settings)
39+
? new Dictionary<string, string>()
40+
: settings
41+
.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)
42+
.Select(s => s.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries))
43+
.Where(a => a.Length == 2)
44+
.ToDictionary(a => $"{ScriptConstants.FunctionsHostingConfigSectionName}:{a[0]}", a => a[1], StringComparer.OrdinalIgnoreCase);
45+
}
46+
}
47+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System;
5+
using Microsoft.Extensions.Configuration;
6+
using Microsoft.Extensions.Configuration.Json;
7+
8+
namespace Microsoft.Azure.WebJobs.Script.Config
9+
{
10+
/// <summary>
11+
/// Represents a JSON file as an <see cref="IConfigurationSource"/>.
12+
/// </summary>
13+
public class FunctionsHostingConfigSource : FileConfigurationSource
14+
{
15+
private readonly string _path;
16+
17+
public FunctionsHostingConfigSource(IEnvironment environment)
18+
{
19+
// If runs on Linux SKUs read from FunctionsPlatformConfigFilePath
20+
_path = environment.GetEnvironmentVariable(EnvironmentSettingNames.FunctionsPlatformConfigFilePath);
21+
if (string.IsNullOrEmpty(_path))
22+
{
23+
// This path is for windows SKUs
24+
_path = Environment.ExpandEnvironmentVariables(System.IO.Path.Combine("%ProgramFiles(x86)%", "SiteExtensions", "kudu", "ScmHostingConfigurations.txt"));
25+
}
26+
}
27+
28+
/// <summary>
29+
/// Builds the <see cref="FunctionsHostingConfigSource"/> for this source.
30+
/// </summary>
31+
/// <param name="builder">The <see cref="IConfigurationBuilder"/>.</param>
32+
/// <returns>A <see cref="FunctionsHostingConfigProvider"/></returns>
33+
public override IConfigurationProvider Build(IConfigurationBuilder builder)
34+
{
35+
Path = _path;
36+
Optional = true;
37+
ReloadOnChange = true;
38+
ResolveFileProvider();
39+
EnsureDefaults(builder);
40+
41+
return new FunctionsHostingConfigProvider(this);
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)