in src/WebJobs.Script/Host/FunctionMetadataManager.cs [228:297]
private void AddMetadataFromCustomProviders(IEnumerable<IFunctionProvider> functionProviders, List<FunctionMetadata> functionMetadataList)
{
_logger.ReadingFunctionMetadataFromProvider(MetadataProviderName);
var functionProviderTasks = new List<Task<ImmutableArray<FunctionMetadata>>>();
var metadataProviderTimeout = _scriptOptions.Value.MetadataProviderTimeout;
foreach (var functionProvider in functionProviders)
{
var getFunctionMetadataFromProviderTask = functionProvider.GetFunctionMetadataAsync();
var delayTask = Task.Delay(metadataProviderTimeout);
var completedTask = Task.WhenAny(getFunctionMetadataFromProviderTask, delayTask).ContinueWith(t =>
{
if (t.Result == getFunctionMetadataFromProviderTask)
{
return getFunctionMetadataFromProviderTask.Result;
}
// Timeout case.
throw new TimeoutException($"Timeout occurred while retrieving metadata from provider '{functionProvider.GetType().FullName}'. The operation exceeded the configured timeout of {metadataProviderTimeout.TotalSeconds} seconds.");
});
functionProviderTasks.Add(completedTask);
}
var providerFunctionMetadataResults = Task.WhenAll(functionProviderTasks).GetAwaiter().GetResult();
var totalFunctionsCount = providerFunctionMetadataResults.Where(metadataArray => !metadataArray.IsDefaultOrEmpty).Sum(metadataArray => metadataArray.Length);
// This is used to make sure no duplicates are registered
var distinctFunctionNames = new HashSet<string>(functionMetadataList.Select(m => m.Name));
_logger.FunctionsReturnedByProvider(totalFunctionsCount, MetadataProviderName);
foreach (var metadataArray in providerFunctionMetadataResults)
{
if (!metadataArray.IsDefaultOrEmpty)
{
foreach (var metadata in metadataArray)
{
if (distinctFunctionNames.Contains(metadata.Name))
{
throw new InvalidOperationException($"Found duplicate {nameof(FunctionMetadata)} with the name {metadata.Name}");
}
// If not explicitly set, consider the function codeless.
if (!metadata.IsCodelessSet())
{
metadata.SetIsCodeless(true);
}
distinctFunctionNames.Add(metadata.Name);
functionMetadataList.Add(metadata);
}
}
}
foreach (var functionProvider in functionProviders)
{
if (functionProvider.FunctionErrors == null)
{
continue;
}
foreach (var errorKvp in functionProvider.FunctionErrors)
{
_functionErrors[errorKvp.Key] = errorKvp.Value.ToList();
}
}
}