internal StreamingMessage ProcessInvocationRequest(StreamingMessage request)
        {
            InvocationRequest invocationRequest = request.InvocationRequest;

            StreamingMessage response = NewStreamingMessageTemplate(
                request.RequestId,
                StreamingMessage.ContentOneofCase.InvocationResponse,
                out StatusResult status);

            response.InvocationResponse.InvocationId = invocationRequest.InvocationId;

            // Invoke powershell logic and return hashtable of out binding data
            try
            {
                // Load information about the function
                var functionInfo = _functionLoader.GetFunctionInfo(invocationRequest.FunctionId);

                Hashtable results = functionInfo.Type == AzFunctionType.OrchestrationFunction
                    ? InvokeOrchestrationFunction(functionInfo, invocationRequest)
                    : InvokeSingleActivityFunction(functionInfo, invocationRequest);

                BindOutputFromResult(response.InvocationResponse, functionInfo, results);
            }
            catch (Exception e)
            {
                status.Status    = StatusResult.Types.Status.Failure;
                status.Exception = e.ToRpcException();
            }

            return(response);
        }
        /// <summary>
        /// Method to process a InvocationRequest.
        /// This method checks out a worker from the pool, and then starts the actual invocation in a threadpool thread.
        /// </summary>
        internal StreamingMessage ProcessInvocationRequest(StreamingMessage request)
        {
            AzFunctionInfo    functionInfo = null;
            PowerShellManager psManager    = null;

            try
            {
                functionInfo = _functionLoader.GetFunctionInfo(request.InvocationRequest.FunctionId);
                psManager    = _powershellPool.CheckoutIdleWorker(request, functionInfo);
                Task.Run(() => ProcessInvocationRequestImpl(request, functionInfo, psManager));
            }
            catch (Exception e)
            {
                _powershellPool.ReclaimUsedWorker(psManager);

                StreamingMessage response = NewStreamingMessageTemplate(
                    request.RequestId,
                    StreamingMessage.ContentOneofCase.InvocationResponse,
                    out StatusResult status);

                response.InvocationResponse.InvocationId = request.InvocationRequest.InvocationId;
                status.Status    = StatusResult.Types.Status.Failure;
                status.Exception = e.ToRpcException();

                return(response);
            }

            return(null);
        }
        /// <summary>
        /// Method to process a InvocationRequest.
        /// This method checks out a worker from the pool, and then starts the actual invocation in a threadpool thread.
        /// </summary>
        internal StreamingMessage ProcessInvocationRequest(StreamingMessage request)
        {
            Exception error = null;

            try
            {
                if (_dependencyManager.DependencyDownloadTask != null &&
                    !_dependencyManager.DependencyDownloadTask.IsCompleted)
                {
                    var rpcLogger = new RpcLogger(_msgStream);
                    rpcLogger.SetContext(request.RequestId, request.InvocationRequest?.InvocationId);
                    rpcLogger.Log(LogLevel.Information, PowerShellWorkerStrings.DependencyDownloadInProgress, isUserLog: true);
                    _dependencyManager.WaitOnDependencyDownload();
                }

                if (_dependencyManager.DependencyError != null)
                {
                    error = _dependencyManager.DependencyError;
                }
                else
                {
                    AzFunctionInfo    functionInfo = FunctionLoader.GetFunctionInfo(request.InvocationRequest.FunctionId);
                    PowerShellManager psManager    = _powershellPool.CheckoutIdleWorker(request, functionInfo);

                    if (_powershellPool.UpperBound == 1)
                    {
                        // When the concurrency upper bound is 1, we can handle only one invocation at a time anyways,
                        // so it's better to just do it on the current thread to reduce the required synchronization.
                        ProcessInvocationRequestImpl(request, functionInfo, psManager);
                    }
                    else
                    {
                        // When the concurrency upper bound is more than 1, we have to handle the invocation in a worker
                        // thread, so multiple invocations can make progress at the same time, even though by time-sharing.
                        Task.Run(() => ProcessInvocationRequestImpl(request, functionInfo, psManager));
                    }
                }
            }
            catch (Exception e)
            {
                error = e;
            }

            if (error != null)
            {
                StreamingMessage response = NewStreamingMessageTemplate(
                    request.RequestId,
                    StreamingMessage.ContentOneofCase.InvocationResponse,
                    out StatusResult status);

                response.InvocationResponse.InvocationId = request.InvocationRequest.InvocationId;
                status.Status    = StatusResult.Types.Status.Failure;
                status.Exception = error.ToRpcException();

                return(response);
            }

            return(null);
        }
Beispiel #4
0
        /// <summary>
        /// Method to process a InvocationRequest.
        /// This method checks out a worker from the pool, and then starts the actual invocation in a threadpool thread.
        /// </summary>
        internal StreamingMessage ProcessInvocationRequest(StreamingMessage request)
        {
            try
            {
                var stopwatch = new FunctionInvocationPerformanceStopwatch();
                stopwatch.OnStart();

                // Will block if installing dependencies is required
                _dependencyManager.WaitForDependenciesAvailability(
                    () =>
                {
                    var rpcLogger = new RpcLogger(_msgStream);
                    rpcLogger.SetContext(request.RequestId, request.InvocationRequest?.InvocationId);
                    return(rpcLogger);
                });

                stopwatch.OnCheckpoint(FunctionInvocationPerformanceStopwatch.Checkpoint.DependenciesAvailable);

                AzFunctionInfo functionInfo = FunctionLoader.GetFunctionInfo(request.InvocationRequest.FunctionId);

                PowerShellManager psManager = _powershellPool.CheckoutIdleWorker(
                    request.RequestId,
                    request.InvocationRequest?.InvocationId,
                    functionInfo.FuncName,
                    functionInfo.OutputBindings);

                stopwatch.OnCheckpoint(FunctionInvocationPerformanceStopwatch.Checkpoint.RunspaceAvailable);

                // When the concurrency upper bound is more than 1, we have to handle the invocation in a worker
                // thread, so multiple invocations can make progress at the same time, even though by time-sharing.
                Task.Run(() => ProcessInvocationRequestImpl(request, functionInfo, psManager, stopwatch));
            }
            catch (Exception e)
            {
                StreamingMessage response = NewStreamingMessageTemplate(
                    request.RequestId,
                    StreamingMessage.ContentOneofCase.InvocationResponse,
                    out StatusResult status);

                response.InvocationResponse.InvocationId = request.InvocationRequest.InvocationId;
                status.Status    = StatusResult.Types.Status.Failure;
                status.Exception = e.ToRpcException();

                return(response);
            }

            return(null);
        }
Beispiel #5
0
        /// <summary>
        /// Method to process a InvocationRequest.
        /// This method checks out a worker from the pool, and then starts the actual invocation in a threadpool thread.
        /// </summary>
        internal StreamingMessage ProcessInvocationRequest(StreamingMessage request)
        {
            try
            {
                // Will block if installing dependencies is required
                _dependencyManager.WaitForDependenciesAvailability(
                    () =>
                {
                    var rpcLogger = new RpcLogger(_msgStream);
                    rpcLogger.SetContext(request.RequestId, request.InvocationRequest?.InvocationId);
                    return(rpcLogger);
                });

                AzFunctionInfo    functionInfo = FunctionLoader.GetFunctionInfo(request.InvocationRequest.FunctionId);
                PowerShellManager psManager    = _powershellPool.CheckoutIdleWorker(request, functionInfo);

                if (_powershellPool.UpperBound == 1)
                {
                    // When the concurrency upper bound is 1, we can handle only one invocation at a time anyways,
                    // so it's better to just do it on the current thread to reduce the required synchronization.
                    ProcessInvocationRequestImpl(request, functionInfo, psManager);
                }
                else
                {
                    // When the concurrency upper bound is more than 1, we have to handle the invocation in a worker
                    // thread, so multiple invocations can make progress at the same time, even though by time-sharing.
                    Task.Run(() => ProcessInvocationRequestImpl(request, functionInfo, psManager));
                }
            }
            catch (Exception e)
            {
                StreamingMessage response = NewStreamingMessageTemplate(
                    request.RequestId,
                    StreamingMessage.ContentOneofCase.InvocationResponse,
                    out StatusResult status);

                response.InvocationResponse.InvocationId = request.InvocationRequest.InvocationId;
                status.Status    = StatusResult.Types.Status.Failure;
                status.Exception = e.ToRpcException();

                return(response);
            }

            return(null);
        }
Beispiel #6
0
        internal StreamingMessage ProcessInvocationRequest(StreamingMessage request)
        {
            InvocationRequest invocationRequest = request.InvocationRequest;

            // Assume success unless something bad happens
            var status = new StatusResult()
            {
                Status = StatusResult.Types.Status.Success
            };
            var response = new StreamingMessage()
            {
                RequestId          = request.RequestId,
                InvocationResponse = new InvocationResponse()
                {
                    InvocationId = invocationRequest.InvocationId,
                    Result       = status
                }
            };

            // Invoke powershell logic and return hashtable of out binding data
            try
            {
                // Load information about the function
                var functionInfo = _functionLoader.GetFunctionInfo(invocationRequest.FunctionId);

                // Bundle all TriggerMetadata into Hashtable to send down to PowerShell
                var triggerMetadata = new Hashtable(StringComparer.OrdinalIgnoreCase);
                foreach (var dataItem in invocationRequest.TriggerMetadata)
                {
                    // MapField<K, V> is case-sensitive, but powershell is case-insensitive,
                    // so for keys differ only in casing, the first wins.
                    if (!triggerMetadata.ContainsKey(dataItem.Key))
                    {
                        triggerMetadata.Add(dataItem.Key, dataItem.Value.ToObject());
                    }
                }

                // Set the RequestId and InvocationId for logging purposes
                Hashtable result = null;
                result = _powerShellManager.InvokeFunction(
                    functionInfo.ScriptPath,
                    functionInfo.EntryPoint,
                    triggerMetadata,
                    invocationRequest.InputData);

                // Set out binding data and return response to be sent back to host
                foreach (KeyValuePair <string, BindingInfo> binding in functionInfo.OutputBindings)
                {
                    // if one of the bindings is '$return' we need to set the ReturnValue
                    if (string.Equals(binding.Key, "$return", StringComparison.OrdinalIgnoreCase))
                    {
                        response.InvocationResponse.ReturnValue = result[binding.Key].ToTypedData();
                        continue;
                    }

                    ParameterBinding paramBinding = new ParameterBinding()
                    {
                        Name = binding.Key,
                        Data = result[binding.Key].ToTypedData()
                    };

                    response.InvocationResponse.OutputData.Add(paramBinding);
                }
            }
            catch (Exception e)
            {
                status.Status    = StatusResult.Types.Status.Failure;
                status.Exception = e.ToRpcException();
            }

            return(response);
        }