/// <summary> /// This method executes the request against the command collection. /// </summary> /// <param name="request">The request state.</param> private async Task TransmitResponses(TransmissionPayloadState request) { //Set the follow on security. request.Responses .Where((p) => p.SecurityPrincipal == null) .ForEach((p) => p.SecurityPrincipal = Thread.CurrentPrincipal as ClaimsPrincipal); //Get the payloads that can be processed internally. var internalPayload = request.Responses .Where((p) => ((request.CurrentOptions & ProcessOptions.RouteInternal) > 0) && mCommands.Resolve(p)) .ToList(); //OK, send the payloads off to the Task Manager for processing. internalPayload.ForEach((p) => { //Mark internal only to stop any looping. //We can do this as we have checked with the command handler that they will be processed p.Options = ProcessOptions.RouteInternal; mTaskManager.ExecuteOrEnqueue(p, "Dispatcher"); }); //Extract the payloads that have been processed internally so that we only have the external payloads left var externalPayload = request.Responses.Except(internalPayload).ToList(); //Send the external payload to their specific destination in paralle;. await Task.WhenAll(externalPayload.Select(async(p) => await TransmitPayload(p, request))); }
/// <summary> /// This method executes the request against the command collection. /// </summary> /// <param name="request">The request state.</param> private async Task ExecuteCommands(TransmissionPayloadState request) { try { request.ExecuteSuccess = await mCommands.Execute(request.Payload, request.Responses); } catch (Exception ex) { request.Ex = ex; } //All good. if (request.ExecuteSuccess) { return; } //Switch the incoming message to the outgoing collection to be processed //by the sender as it has not been processed internally. This will happen if it //is not marked as internal only and cannot be resolved locally. if (!request.InternalOnly) { //OK, we are going to send this to the senders, first make sure that this doesn't route back in. request.CurrentOptions = ProcessOptions.RouteExternal; //Switch the incoming message to the response payload so that they are picked up by the senders. request.Responses.Add(request.Payload); return; } ProcessUnhandledPayload(Policies.Microservice.DispatcherUnresolvedRequestMode , DispatcherRequestUnresolvedReason.MessageHandlerNotFound , request.Payload); }
/// <summary> /// This method transits a payload and captures and exceptions. /// </summary> /// <param name="payload">The payload to process.</param> /// <param name="request">The request state.</param> private async Task TransmitPayload(TransmissionPayload payload, TransmissionPayloadState request) { try { request.TransmitSuccess &= await Send(payload); } catch (Exception ex) { request.Ex = ex; request.TransmitSuccess = false; } }
/// <summary> /// This method executes the request against the command collection. /// </summary> /// <param name="request">The request state.</param> private async Task ExecuteCommands(TransmissionPayloadState request) { try { request.ExecuteSuccess = await mCommands.Execute(request.Payload, request.Responses); } catch (Exception ex) { request.Ex = ex; } //All good. if (request.ExecuteSuccess) { return; } //Switch the incoming message to the outgoing collection to be processed //by the sender as it has not been processed internally. This will happen if it //is not marked as internal only and cannot be resolved locally. if (!request.InternalOnly) { //OK, we are going to send this to the senders, first make sure that this doesn't route back in. request.CurrentOptions = ProcessOptions.RouteExternal; //Switch the incoming message to the response payload so that they are picked up by the senders. request.Responses.Add(request.Payload); return; } //OK, we have an problem. We log this as an error and get out of here. mDataCollection.DispatcherPayloadUnresolved(request.Payload, DispatcherRequestUnresolvedReason.MessageHandler); //Raise an event for the unresolved wrapper mEventsWrapper.OnProcessRequestUnresolved(request.Payload, DispatcherRequestUnresolvedReason.MessageHandler); switch (Policy.Microservice.DispatcherUnhandledMode) { case DispatcherUnhandledMessageAction.Ignore: //request.IsSuccess = !request.IsFaulted; break; case DispatcherUnhandledMessageAction.AttemptResponseFailMessage: //request.IsSuccess = true; break; case DispatcherUnhandledMessageAction.Exception: //request.IsSuccess = true; break; } }
/// <summary> /// This is the core method that messages are sent to to be routed and processed. /// You can override this task in your service to help debug the messages that are passing /// though. /// </summary> /// <param name="requestPayload">The request payload.</param> protected virtual async Task Execute(TransmissionPayload requestPayload) { var request = new TransmissionPayloadState(requestPayload , Policy.Microservice.DispatcherTransitCountMax , StatisticsInternal.ActiveIncrement()); try { Thread.CurrentPrincipal = request.Payload.SecurityPrincipal; mEventsWrapper.OnExecuteBegin(request); //Validate the imcoming request is correct and not cancelled. request.IncomingValidate(); //Log the telemtry for the incoming message. mDataCollection.DispatcherPayloadIncoming(request.Payload); //Check that we have not exceeded the maximum transit count. request.IncrementAndVerifyDispatcherTransitCount(); //Shortcut for external messages - send straight out if (request.ExternalOnly) { await TransmitPayload(request.Payload, request); } else { //Execute the message against the internal commands await ExecuteCommands(request); //OK, do we have any response from the commands to send on, both internal and external messages? if (request.Responses.Count > 0) { await TransmitResponses(request); } } } catch (DispatcherException dex) { mDataCollection.DispatcherPayloadException(dex.Payload, dex); mEventsWrapper.OnProcessRequestError(dex.Payload, dex); } catch (Exception ex) { mDataCollection.DispatcherPayloadException(request.Payload, ex); mEventsWrapper.OnProcessRequestError(request.Payload, ex); } finally { //Signal to the underlying listener that the message can be released. request.Signal(); int delta = StatisticsInternal.ActiveDecrement(request.TimerStart); //Log the telemtry for the specific message channelId. mDataCollection.DispatcherPayloadComplete(request.Payload, delta, request.IsSuccess()); if (!request.IsSuccess()) { StatisticsInternal.ErrorIncrement(); } mEventsWrapper.OnExecuteComplete(request); //Set the thread principal to null before leaving. Thread.CurrentPrincipal = null; } }