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