public void AddLockRequestToBatch(RequestMessage lockRequest) { this.lockRequest = lockRequest; }
public void AddOperationToBatch(RequestMessage operationMessage) { this.operationBatch.Add(operationMessage); }
private async Task ProcessOperationRequestAsync(RequestMessage request) { // set context for operation this.context.CurrentOperation = request; this.context.CurrentOperationResponse = new ResponseMessage(); // set the async-local static context that is visible to the application code Entity.SetContext(this.context); bool operationFailed = false; var initialOutboxPosition = this.context.OutboxPosition; var stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Start(); string exceptionDetails = string.Empty; try { Task invokeTask = this.FunctionInvocationCallback(); if (invokeTask is Task resultTask) { await resultTask; stopwatch.Stop(); } else { throw new InvalidOperationException("The WebJobs runtime returned a invocation task that is not awaitable!"); } } catch (Exception e) { stopwatch.Stop(); exceptionDetails = e.ToString(); this.context.CaptureApplicationError(e); // exception must be sent with response back to caller this.context.CurrentOperationResponse.SetExceptionResult( e, this.context.CurrentOperation.Operation, this.errorDataConverter); operationFailed = true; } if (this.RollbackFailedOperations) { // we write back the entity state after each successful operation if (!operationFailed) { if (!this.context.TryWriteback(out var errorResponseMessage)) { // state serialization failed; create error response and roll back. this.context.CurrentOperationResponse = errorResponseMessage; operationFailed = true; } } if (operationFailed) { // discard changes and don't send any signals this.context.Rollback(initialOutboxPosition); } } // clear the async-local static context that is visible to the application code Entity.SetContext(null); // read and clear context var response = this.context.CurrentOperationResponse; this.context.CurrentOperation = null; this.context.CurrentOperationResponse = null; if (!operationFailed) { this.Config.TraceHelper.OperationCompleted( this.context.HubName, this.context.Name, this.context.InstanceId, request.Id.ToString(), request.Operation, this.Config.GetIntputOutputTrace(this.context.RawInput), this.Config.GetIntputOutputTrace(response.Result), stopwatch.Elapsed.TotalMilliseconds, isReplay: false); } else { this.Config.TraceHelper.OperationFailed( this.context.HubName, this.context.Name, this.context.InstanceId, request.Id.ToString(), request.Operation, this.Config.GetIntputOutputTrace(this.context.RawInput), exceptionDetails, stopwatch.Elapsed.TotalMilliseconds, isReplay: false); } // send response if (!request.IsSignal) { var target = new OrchestrationInstance() { InstanceId = request.ParentInstanceId, ExecutionId = request.ParentExecutionId }; var jresponse = JToken.FromObject(response, this.messageDataConverter.JsonSerializer); this.context.SendResponseMessage(target, request.Id, jresponse, response.IsException); } }
private async Task ExecuteOutOfProcBatch() { object outOfProcResults = null; Task invokeTask = this.FunctionInvocationCallback(); if (invokeTask is Task <object> resultTask) { outOfProcResults = await resultTask; } else { throw new InvalidOperationException("The WebJobs runtime returned a invocation task that does not support return values!"); } var jObj = outOfProcResults as JObject; if (jObj == null) { throw new ArgumentException("Out of proc orchestrators must return a valid JSON schema."); } var outOfProcResult = jObj.ToObject <OutOfProcResult>(); // update the state this.context.State.EntityExists = outOfProcResult.EntityExists; this.context.State.EntityState = outOfProcResult.EntityState; // for each operation, emit trace and send response message (if not a signal) for (int i = 0; i < this.OperationBatch.Count; i++) { var request = this.OperationBatch[i]; var result = outOfProcResult.Results[i]; if (!result.IsError) { this.Config.TraceHelper.OperationCompleted( this.context.HubName, this.context.Name, this.context.InstanceId, request.Id.ToString(), request.Operation, this.Config.GetIntputOutputTrace(request.Input), this.Config.GetIntputOutputTrace(result.Result), result.DurationInMilliseconds, isReplay: false); } else { this.context.CaptureApplicationError(new OperationErrorException( $"Error in operation '{request.Operation}': {result}")); this.Config.TraceHelper.OperationFailed( this.context.HubName, this.context.Name, this.context.InstanceId, request.Id.ToString(), request.Operation, this.Config.GetIntputOutputTrace(request.Input), this.Config.GetIntputOutputTrace(result.Result), result.DurationInMilliseconds, isReplay: false); } if (!request.IsSignal) { var target = new OrchestrationInstance() { InstanceId = request.ParentInstanceId, ExecutionId = request.ParentExecutionId, }; var responseMessage = new ResponseMessage() { Result = result.Result, ExceptionType = result.IsError ? "Error" : null, }; this.context.SendResponseMessage(target, request.Id, responseMessage, !result.IsError); } } // send signal messages foreach (var signal in outOfProcResult.Signals) { var request = new RequestMessage() { ParentInstanceId = this.context.InstanceId, ParentExecutionId = null, // for entities, message sorter persists across executions Id = Guid.NewGuid(), IsSignal = true, Operation = signal.Name, Input = signal.Input, }; var target = new OrchestrationInstance() { InstanceId = EntityId.GetSchedulerIdFromEntityId(signal.Target), }; this.context.SendOperationMessage(target, request); } }
private async Task ProcessOperationRequestAsync(RequestMessage request) { // set context for operation this.context.CurrentOperation = request; this.context.CurrentOperationResponse = new ResponseMessage(); // set the async-local static context that is visible to the application code Entity.SetContext(this.context); var stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Start(); string exceptionDetails = string.Empty; try { Task invokeTask = this.FunctionInvocationCallback(); if (invokeTask is Task resultTask) { await resultTask; stopwatch.Stop(); } else { throw new InvalidOperationException("The WebJobs runtime returned a invocation task that is not awaitable!"); } } catch (Exception e) { stopwatch.Stop(); exceptionDetails = e.ToString(); this.context.CaptureApplicationError(e); // exception must be sent with response back to caller this.context.CurrentOperationResponse.SetExceptionResult(e, this.context.CurrentOperation.Operation, this.EntityId); } // clear the async-local static context that is visible to the application code Entity.SetContext(null); // read and clear context var response = this.context.CurrentOperationResponse; this.context.CurrentOperation = null; this.context.CurrentOperationResponse = null; if (!response.IsException) { this.Config.TraceHelper.OperationCompleted( this.context.HubName, this.context.Name, this.context.InstanceId, request.Id.ToString(), request.Operation, this.Config.GetIntputOutputTrace(this.context.RawInput), this.Config.GetIntputOutputTrace(response.Result), stopwatch.Elapsed.TotalMilliseconds, isReplay: false); } else { this.Config.TraceHelper.OperationFailed( this.context.HubName, this.context.Name, this.context.InstanceId, request.Id.ToString(), request.Operation, this.Config.GetIntputOutputTrace(this.context.RawInput), exceptionDetails, stopwatch.Elapsed.TotalMilliseconds, isReplay: false); } // send response if (!request.IsSignal) { var target = new OrchestrationInstance() { InstanceId = request.ParentInstanceId }; var guid = request.Id.ToString(); var jresponse = JToken.FromObject(response, MessagePayloadDataConverter.DefaultSerializer); this.context.SendResponseMessage(target, guid, jresponse, !response.IsException); } }