Skip to content

Commit 265dc83

Browse files
authored
Implementing selective loading for stein (#8939)
1 parent fa21091 commit 265dc83

27 files changed

+521
-587
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,9 @@ public Task<List<RawFunctionMetadata>> GetFunctionMetadata()
535535

536536
internal Task<List<RawFunctionMetadata>> SendFunctionMetadataRequest()
537537
{
538+
// reset indexing task when in case we need to send another request
539+
_functionsIndexingTask = new TaskCompletionSource<List<RawFunctionMetadata>>(TaskCreationOptions.RunContinuationsAsynchronously);
540+
538541
_eventSubscriptions.Add(_inboundWorkerEvents.Where(msg => msg.MessageType == MsgType.FunctionMetadataResponse)
539542
.Timeout(_functionLoadTimeout)
540543
.Take(1)

src/WebJobs.Script.WebHost/WebHostServiceCollectionExtensions.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ public static void AddWebJobsScriptHost(this IServiceCollection services, IConfi
124124
// Management services
125125
services.AddSingleton<IFunctionsSyncManager, FunctionsSyncManager>();
126126
services.AddSingleton<IFunctionMetadataManager, FunctionMetadataManager>();
127-
services.AddSingleton<IFunctionMetadataProvider, HostFunctionMetadataProvider>();
128127
services.AddSingleton<IWebFunctionsManager, WebFunctionsManager>();
129128
services.AddSingleton<IInstanceManager, InstanceManager>();
130129
services.AddSingleton(_ => new HttpClient());
@@ -158,6 +157,14 @@ public static void AddWebJobsScriptHost(this IServiceCollection services, IConfi
158157
// Language Worker Hosted Services need to be intialized before WebJobsScriptHostService
159158
ScriptHostBuilderExtensions.AddCommonServices(services);
160159

160+
services.AddSingleton<IFunctionMetadataProvider>(sp =>
161+
{
162+
return new FunctionMetadataProvider(
163+
sp.GetRequiredService<ILogger<FunctionMetadataProvider>>(),
164+
ActivatorUtilities.CreateInstance<WorkerFunctionMetadataProvider>(sp),
165+
ActivatorUtilities.CreateInstance<HostFunctionMetadataProvider>(sp));
166+
});
167+
161168
// Core script host services
162169
services.AddSingleton<WebJobsScriptHostService>();
163170
services.AddSingleton<IHostedService>(s => s.GetRequiredService<WebJobsScriptHostService>());

src/WebJobs.Script/DependencyInjection/ScriptStartupTypeLocator.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,9 @@ public async Task<IEnumerable<Type>> GetExtensionsStartupTypesAsync()
7676
bool isLegacyExtensionBundle = _extensionBundleManager.IsLegacyExtensionBundle();
7777
bool isPrecompiledFunctionApp = false;
7878

79-
// if workerIndexing
80-
// Function.json (httpTrigger, blobTrigger, blobTrigger) -> httpTrigger, blobTrigger
8179
// dotnet app precompiled -> Do not use bundles
8280
var workerConfigs = _languageWorkerOptions.Value.WorkerConfigs;
83-
if (bundleConfigured && !Utility.CanWorkerIndex(workerConfigs, SystemEnvironment.Instance))
81+
if (bundleConfigured)
8482
{
8583
var functionMetadataCollection = _functionMetadataManager.GetFunctionMetadata(forceRefresh: true, includeCustomProviders: false);
8684
bindingsSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
@@ -164,8 +162,7 @@ public async Task<IEnumerable<Type>> GetExtensionsStartupTypesAsync()
164162

165163
foreach (var extensionItem in extensionItems)
166164
{
167-
if (Utility.CanWorkerIndex(workerConfigs, SystemEnvironment.Instance)
168-
|| !bundleConfigured
165+
if (!bundleConfigured
169166
|| extensionItem.Bindings.Count == 0
170167
|| extensionItem.Bindings.Intersect(bindingsSet, StringComparer.OrdinalIgnoreCase).Any())
171168
{

src/WebJobs.Script/Host/FunctionMetadataManager.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using Microsoft.Azure.WebJobs.Script.Workers.Http;
1515
using Microsoft.Azure.WebJobs.Script.Workers.Rpc;
1616
using Microsoft.Extensions.DependencyInjection;
17+
using Microsoft.Extensions.Hosting;
1718
using Microsoft.Extensions.Logging;
1819
using Microsoft.Extensions.Options;
1920

@@ -81,11 +82,11 @@ public bool TryGetFunctionMetadata(string functionName, out FunctionMetadata fun
8182
/// <param name="applyAllowList">Apply functions allow list filter.</param>
8283
/// <param name="includeCustomProviders">Include any metadata provided by IFunctionProvider when loading the metadata</param>
8384
/// <returns> An Immmutable array of FunctionMetadata.</returns>
84-
public ImmutableArray<FunctionMetadata> GetFunctionMetadata(bool forceRefresh, bool applyAllowList = true, bool includeCustomProviders = true, IFunctionInvocationDispatcher dispatcher = null)
85+
public ImmutableArray<FunctionMetadata> GetFunctionMetadata(bool forceRefresh, bool applyAllowList = true, bool includeCustomProviders = true)
8586
{
8687
if (forceRefresh || _servicesReset || _functionMetadataArray.IsDefaultOrEmpty)
8788
{
88-
_functionMetadataArray = LoadFunctionMetadata(forceRefresh, includeCustomProviders, dispatcher);
89+
_functionMetadataArray = LoadFunctionMetadata(forceRefresh, includeCustomProviders);
8990
_logger.FunctionMetadataManagerFunctionsLoaded(ApplyAllowList(_functionMetadataArray).Count());
9091
_servicesReset = false;
9192
}
@@ -132,9 +133,7 @@ internal ImmutableArray<FunctionMetadata> LoadFunctionMetadata(bool forceRefresh
132133
ImmutableArray<FunctionMetadata> immutableFunctionMetadata;
133134
var workerConfigs = _languageWorkerOptions.Value.WorkerConfigs;
134135

135-
IFunctionMetadataProvider metadataProvider = new AggregateFunctionMetadataProvider(_loggerFactory.CreateLogger<AggregateFunctionMetadataProvider>(), dispatcher, _functionMetadataProvider, _scriptOptions);
136-
137-
immutableFunctionMetadata = metadataProvider.GetFunctionMetadataAsync(workerConfigs, SystemEnvironment.Instance, forceRefresh).GetAwaiter().GetResult();
136+
immutableFunctionMetadata = _functionMetadataProvider.GetFunctionMetadataAsync(workerConfigs, SystemEnvironment.Instance, forceRefresh).GetAwaiter().GetResult();
138137

139138
var functionMetadataList = new List<FunctionMetadata>();
140139
_functionErrors = new Dictionary<string, ICollection<string>>();
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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.Collections.Immutable;
7+
using System.Threading.Tasks;
8+
using Microsoft.Azure.WebJobs.Script.Description;
9+
using Microsoft.Azure.WebJobs.Script.Workers.Rpc;
10+
using Microsoft.Extensions.Logging;
11+
using Microsoft.Extensions.Options;
12+
13+
namespace Microsoft.Azure.WebJobs.Script.WebHost
14+
{
15+
internal class FunctionMetadataProvider : IFunctionMetadataProvider
16+
{
17+
private readonly IEnvironment _environment;
18+
private readonly ILogger<FunctionMetadataProvider> _logger;
19+
private IWorkerFunctionMetadataProvider _workerFunctionMetadataProvider;
20+
private IHostFunctionMetadataProvider _hostFunctionMetadataProvider;
21+
22+
public FunctionMetadataProvider(ILogger<FunctionMetadataProvider> logger, IWorkerFunctionMetadataProvider workerFunctionMetadataProvider, IHostFunctionMetadataProvider hostFunctionMetadataProvider)
23+
{
24+
_logger = logger;
25+
_workerFunctionMetadataProvider = workerFunctionMetadataProvider;
26+
_hostFunctionMetadataProvider = hostFunctionMetadataProvider;
27+
_environment = SystemEnvironment.Instance;
28+
}
29+
30+
public ImmutableDictionary<string, ImmutableArray<string>> FunctionErrors { get; private set; }
31+
32+
public async Task<ImmutableArray<FunctionMetadata>> GetFunctionMetadataAsync(IEnumerable<RpcWorkerConfig> workerConfigs, IEnvironment environment, bool forceRefresh = false)
33+
{
34+
bool workerIndexing = Utility.CanWorkerIndex(workerConfigs, _environment);
35+
if (!workerIndexing)
36+
{
37+
return await GetMetadataFromHostProvider(workerConfigs, environment, forceRefresh);
38+
}
39+
40+
_logger.LogInformation("Worker indexing is enabled");
41+
42+
FunctionMetadataResult functionMetadataResult = await _workerFunctionMetadataProvider?.GetFunctionMetadataAsync(workerConfigs, SystemEnvironment.Instance, forceRefresh);
43+
FunctionErrors = _workerFunctionMetadataProvider.FunctionErrors;
44+
45+
if (functionMetadataResult.UseDefaultMetadataIndexing)
46+
{
47+
_logger.LogDebug("Fallback to host indexing as worker denied indexing");
48+
return await GetMetadataFromHostProvider(workerConfigs, environment, forceRefresh);
49+
}
50+
51+
return functionMetadataResult.Functions;
52+
}
53+
54+
private async Task<ImmutableArray<FunctionMetadata>> GetMetadataFromHostProvider(IEnumerable<RpcWorkerConfig> workerConfigs, IEnvironment environment, bool forceRefresh = false)
55+
{
56+
var functions = await _hostFunctionMetadataProvider?.GetFunctionMetadataAsync(workerConfigs, environment, forceRefresh);
57+
FunctionErrors = _hostFunctionMetadataProvider.FunctionErrors;
58+
return functions;
59+
}
60+
}
61+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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.Immutable;
5+
using Microsoft.Azure.WebJobs.Script.Description;
6+
7+
namespace Microsoft.Azure.WebJobs.Script
8+
{
9+
internal class FunctionMetadataResult
10+
{
11+
public FunctionMetadataResult(bool useDefaultMetadataIndexing, ImmutableArray<FunctionMetadata> functions)
12+
{
13+
this.UseDefaultMetadataIndexing = useDefaultMetadataIndexing;
14+
this.Functions = functions;
15+
}
16+
17+
public bool UseDefaultMetadataIndexing { get; private set; }
18+
19+
public ImmutableArray<FunctionMetadata> Functions { get; private set; }
20+
}
21+
}

src/WebJobs.Script/Host/HostFunctionMetadataProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
namespace Microsoft.Azure.WebJobs.Script
2222
{
23-
public class HostFunctionMetadataProvider : IFunctionMetadataProvider
23+
internal class HostFunctionMetadataProvider : IHostFunctionMetadataProvider
2424
{
2525
private readonly IOptionsMonitor<ScriptApplicationHostOptions> _applicationHostOptions;
2626
private readonly IMetricsLogger _metricsLogger;

src/WebJobs.Script/Host/IFunctionMetadataManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public interface IFunctionMetadataManager
1111
{
1212
ImmutableDictionary<string, ImmutableArray<string>> Errors { get; }
1313

14-
ImmutableArray<FunctionMetadata> GetFunctionMetadata(bool forceRefresh = false, bool applyAllowlist = true, bool includeCustomProviders = true, IFunctionInvocationDispatcher dispatcher = null);
14+
ImmutableArray<FunctionMetadata> GetFunctionMetadata(bool forceRefresh = false, bool applyAllowlist = true, bool includeCustomProviders = true);
1515

1616
bool TryGetFunctionMetadata(string functionName, out FunctionMetadata functionMetadata, bool forceRefresh = false);
1717
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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 System.Collections.Immutable;
6+
using System.Threading.Tasks;
7+
using Microsoft.Azure.WebJobs.Script.Description;
8+
using Microsoft.Azure.WebJobs.Script.Workers.Rpc;
9+
10+
namespace Microsoft.Azure.WebJobs.Script
11+
{
12+
/// <summary>
13+
/// Defines an interface for fetching function metadata from function.json files
14+
/// </summary>
15+
internal interface IHostFunctionMetadataProvider
16+
{
17+
ImmutableDictionary<string, ImmutableArray<string>> FunctionErrors { get; }
18+
19+
/// <summary>
20+
/// Reads function metadata from function.json files present along with each function
21+
/// </summary>
22+
Task<ImmutableArray<FunctionMetadata>> GetFunctionMetadataAsync(IEnumerable<RpcWorkerConfig> workerConfigs, IEnvironment environment, bool forceRefresh = false);
23+
}
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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 System.Collections.Immutable;
6+
using System.Threading.Tasks;
7+
using Microsoft.Azure.WebJobs.Script.Workers.Rpc;
8+
9+
namespace Microsoft.Azure.WebJobs.Script
10+
{
11+
/// <summary>
12+
/// Defines an interface for fetching function metadata from Out-of-Proc language workers
13+
/// </summary>
14+
internal interface IWorkerFunctionMetadataProvider
15+
{
16+
ImmutableDictionary<string, ImmutableArray<string>> FunctionErrors { get; }
17+
18+
/// <summary>
19+
/// Attempts to get function metadata from Out-of-Proc language workers
20+
/// </summary>
21+
/// <returns>FunctionMetadataResult that either contains the function metadata or indicates that a fall back option for fetching metadata should be used</returns>
22+
Task<FunctionMetadataResult> GetFunctionMetadataAsync(IEnumerable<RpcWorkerConfig> workerConfigs, IEnvironment environment, bool forceRefresh = false);
23+
}
24+
}

0 commit comments

Comments
 (0)