public async Task GetFunctionMetadataAsync()

in src/WebJobs.Script/Host/WorkerFunctionMetadataProvider.cs [53:150]


        public async Task<FunctionMetadataResult> GetFunctionMetadataAsync(IEnumerable<RpcWorkerConfig> workerConfigs, bool forceRefresh)
        {
            _workerRuntime = _environment.GetEnvironmentVariable(EnvironmentSettingNames.FunctionWorkerRuntime);

            _logger.LogInformation("Fetching metadata for workerRuntime: {workerRuntime}", _workerRuntime);

            IEnumerable<FunctionMetadata> functions = new List<FunctionMetadata>();
            _logger.ReadingFunctionMetadataFromProvider(_metadataProviderName);

            if (_functions.IsDefaultOrEmpty || forceRefresh)
            {
                IEnumerable<RawFunctionMetadata> rawFunctions = new List<RawFunctionMetadata>();

                if (_channelManager == null)
                {
                    throw new InvalidOperationException(nameof(_channelManager));
                }

                // Scenario: Restart worker for hot reload on a readwrite file system
                // We reuse the worker started in placeholderMode only when the fileSystem is readonly
                // otherwise we shutdown the channel in which case the channel should not have any channels anyway
                // forceRefresh in only true once in the script host initialization flow.
                // forceRefresh will be false when bundle is not used (dotnet and dotnet-isolated).
                if (!_environment.IsPlaceholderModeEnabled() && forceRefresh && !_scriptOptions.CurrentValue.IsFileSystemReadOnly)
                {
                    _channelManager.ShutdownChannelsAsync().GetAwaiter().GetResult();
                }

                var channels = _channelManager.GetChannels(_workerRuntime);

                // Start up GRPC channels if they are not already running.
                if (channels?.Any() != true)
                {
                    if (_scriptHostManager.State is ScriptHostState.Default
                        || _scriptHostManager.State is ScriptHostState.Starting
                        || _scriptHostManager.State is ScriptHostState.Initialized)
                    {
                        // We don't need to restart if the host hasn't even been created yet.
                        _logger.LogDebug("Host is starting up, initializing language worker channel");
                        await _channelManager.InitializeChannelAsync(workerConfigs, _workerRuntime);
                    }
                    else
                    {
                        // During the restart flow, GetFunctionMetadataAsync gets invoked
                        // again through a new script host initialization flow.
                        _logger.LogDebug("Host is running without any initialized channels, restarting the JobHost.");
                        await _scriptHostManager.RestartHostAsync();
                    }

                    channels = _channelManager.GetChannels(_workerRuntime);
                }

                if (channels is null)
                {
                    _logger.LogDebug("Worker channels are null, there is likely an issue with the worker not being able to start.");
                    throw new InvalidOperationException($"No initialized language worker channel found for runtime: {_workerRuntime}.");
                }

                foreach (string workerId in channels.Keys.ToList())
                {
                    if (channels.TryGetValue(workerId, out TaskCompletionSource<IRpcWorkerChannel> languageWorkerChannelTask))
                    {
                        _logger.LogDebug("Found initialized language worker channel for runtime: {workerRuntime} workerId:{workerId}", _workerRuntime, workerId);
                        try
                        {
                            IRpcWorkerChannel channel = await languageWorkerChannelTask.Task;
                            rawFunctions = await channel.GetFunctionMetadata();

                            if (rawFunctions.Any(x => x.UseDefaultMetadataIndexing))
                            {
                                _functions.Clear();
                                return new FunctionMetadataResult(useDefaultMetadataIndexing: true, _functions);
                            }

                            if (!IsNullOrEmpty(rawFunctions))
                            {
                                functions = ValidateMetadata(rawFunctions);
                            }

                            _functions = functions.ToImmutableArray();
                            _logger.FunctionsReturnedByProvider(_functions.IsDefault ? 0 : _functions.Count(), _metadataProviderName);

                            // Validate if the app has functions in legacy format and add in logs to inform about the mixed app
                            _ = Task.Delay(TimeSpan.FromMinutes(1)).ContinueWith(t => ValidateFunctionAppFormat(_scriptOptions.CurrentValue.ScriptPath, _logger, _environment));

                            break;
                        }
                        catch (Exception ex)
                        {
                            _logger.LogWarning(ex, "Removing errored webhost language worker channel for runtime: {workerRuntime} workerId:{workerId}", _workerRuntime, workerId);
                            await _channelManager.ShutdownChannelIfExistsAsync(_workerRuntime, workerId, ex);
                        }
                    }
                }
            }

            return new FunctionMetadataResult(useDefaultMetadataIndexing: false, _functions);
        }