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;
}