internal StreamingMessage ProcessFunctionLoadRequest()

in src/RequestProcessor.cs [183:265]


        internal StreamingMessage ProcessFunctionLoadRequest(StreamingMessage request)
        {
            var stopwatch = new Stopwatch();
            stopwatch.Start();

            FunctionLoadRequest functionLoadRequest = request.FunctionLoadRequest;

            StreamingMessage response = NewStreamingMessageTemplate(
                request.RequestId,
                StreamingMessage.ContentOneofCase.FunctionLoadResponse,
                out StatusResult status);
            response.FunctionLoadResponse.FunctionId = functionLoadRequest.FunctionId;

            // The worker may occasionally receive multiple function load requests with
            // the same FunctionId. In order to make function load request idempotent,
            // the worker should ignore the duplicates.
            if (FunctionLoader.IsLoaded(functionLoadRequest.FunctionId))
            {
                // If FunctionLoader considers this function loaded, this means
                // the previous request was successful, so respond accordingly.
                return response;
            }

            // When a functionLoadRequest comes in, we check to see if a dependency download has failed in a previous call
            // or if PowerShell could not be initialized. If this is the case, mark this as a failed request
            // and submit the exception to the Host (runtime).
            if (_initTerminatingError != null)
            {
                status.Status = StatusResult.Types.Status.Failure;
                status.Exception = _initTerminatingError.ToRpcException();
                return response;
            }

            // Ideally, the initialization should happen when processing 'WorkerInitRequest'. However, we defer the initialization
            // until the first 'FunctionLoadRequest' which contains the information about whether Managed Dependencies is enabled for the function app,
            // and if it is, we add the Managed Dependencies path to the PSModulePath.
            // Also, we receive a FunctionLoadRequest when a proxy is configured. This is just a no-op on the worker size, so we skip over them.
            if (!_isFunctionAppInitialized && !functionLoadRequest.Metadata.IsProxy)
            {
                try
                {
                    _isFunctionAppInitialized = true;

                    var rpcLogger = new RpcLogger(_msgStream);
                    rpcLogger.SetContext(request.RequestId, null);

                    _dependencyManager = new DependencyManager(request.FunctionLoadRequest.Metadata.Directory, logger: rpcLogger);
                    var managedDependenciesPath = _dependencyManager.Initialize(request, rpcLogger);

                    SetupAppRootPathAndModulePath(functionLoadRequest, managedDependenciesPath);

                    _powershellPool.Initialize(_firstPwshInstance);

                    // Start the download asynchronously if needed.
                    _dependencyManager.StartDependencyInstallationIfNeeded(request, _firstPwshInstance, rpcLogger);

                    rpcLogger.Log(isUserOnlyLog: false, LogLevel.Trace, string.Format(PowerShellWorkerStrings.FirstFunctionLoadCompleted, stopwatch.ElapsedMilliseconds));
                }
                catch (Exception e)
                {
                    // Failure that happens during this step is terminating and we will need to return a failure response to
                    // all subsequent 'FunctionLoadRequest'. Cache the exception so we can reuse it in future calls.
                    _initTerminatingError = e;

                    status.Status = StatusResult.Types.Status.Failure;
                    status.Exception = e.ToRpcException();
                    return response;
                }
            }

            try
            {
                // Load the metadata of the function.
                FunctionLoader.LoadFunction(functionLoadRequest);
            }
            catch (Exception e)
            {
                status.Status = StatusResult.Types.Status.Failure;
                status.Exception = e.ToRpcException();
            }

            return response;
        }