/// <summary>
        /// This method resolves the client and processes the message.
        /// </summary>
        /// <param name="payload">The payload to transmit.</param>
        public virtual async Task SenderTransmit(TransmissionPayload payload)
        {
            int?         start  = null;
            ClientHolder sender = null;

            try
            {
                sender = SenderClientResolve(payload.Message.ChannelPriority);

                start = sender.StatisticsInternal.ActiveIncrement();

                await sender.Transmit(payload);

                payload.TraceWrite($"Sent: {sender.Name}", "MessagingSenderBase/ProcessMessage");
            }
            catch (Exception ex)
            {
                LogExceptionLocation($"{nameof(SenderTransmit)} (Unhandled)", ex);
                //OK, not sure what happened here, so we need to throw the exception.
                payload.TraceWrite($"Exception: {ex.Message}", "MessagingSenderBase/ProcessMessage");
                if (sender != null)
                {
                    sender.StatisticsInternal.ErrorIncrement();
                }
                throw;
            }
            finally
            {
                if (sender != null && start.HasValue)
                {
                    sender.StatisticsInternal.ActiveDecrement(start.Value);
                }
            }
        }
        /// <summary>
        /// This method resolves the client and processes the message.
        /// </summary>
        /// <param name="payload">The payload to transmit.</param>
        public virtual async Task ProcessMessage(TransmissionPayload payload)
        {
            int?start  = null;
            H   client = null;

            try
            {
                client = ClientResolve(payload.Message.ChannelPriority);
                start  = client.Statistics.ActiveIncrement();
                await client.Transmit(payload);

                payload.TraceWrite($"Sent: {client.Name}", "MessagingSenderBase/ProcessMessage");
            }
            catch (Exception ex)
            {
                LogExceptionLocation("ProcessMessage (Unhandled)", ex);
                //OK, not sure what happened here, so we need to throw the exception.
                payload.TraceWrite($"Exception: {ex.Message}", "MessagingSenderBase/ProcessMessage");
                if (client != null)
                {
                    client.Statistics.ErrorIncrement();
                }
                throw;
            }
            finally
            {
                if (client != null && start.HasValue)
                {
                    client.Statistics.ActiveDecrement(start.Value);
                }
            }
        }
Beispiel #3
0
        /// <summary>
        /// This method processes an individual payload returned from a client.
        /// </summary>
        /// <param name="clientId">The originating client.</param>
        /// <param name="payload">The payload.</param>
        private void PayloadSubmit(Guid clientId, TransmissionPayload payload)
        {
            try
            {
                payload.TraceConfigure(mPolicy.TransmissionPayloadTraceEnabled);
                payload.TraceWrite("Incoming", "CommunicationContainer/PayloadSubmit");

                //Ensure the priority cannot spoof the internal priority of -1
                if (payload.Message.ChannelPriority < 0)
                {
                    payload.Message.ChannelPriority = 0;
                }

                mClientCollection.QueueTimeLog(clientId, payload.Message.EnqueuedTimeUTC);

                //Verify the incoming payload with the security container.
                PayloadIncomingSecurity(payload);

                //Do we need to redirect the payload based on the redirect/rewrite rules.
                PayloadIncomingRedirectCheck(payload);

                //Create the tracker to process the incoming
                TaskTracker tracker = TaskManager.TrackerCreateFromPayload(payload, payload.Source);

                //Set the function that executes when the payload completes.
                tracker.ExecuteComplete = (tr, failed, ex) =>
                {
                    var contextPayload = tr.ToTransmissionPayload();
                    try
                    {
                        mClientCollection.ActiveDecrement(clientId, tr.TickCount);

                        if (failed)
                        {
                            mClientCollection.ErrorIncrement(clientId);
                        }

                        contextPayload.Signal(!failed);

                        contextPayload.TraceWrite(failed?"Failed":"Success", "CommunicationContainer/PayloadSubmit -> ExecuteComplete");
                    }
                    catch (Exception exin)
                    {
                        Collector?.LogException($"Payload completion error-{payload} after {(tr.Context as TransmissionPayload)?.Message?.FabricDeliveryCount} delivery attempts", exin);
                        contextPayload.TraceWrite($"Exception: {ex.Message}", "CommunicationContainer/PayloadSubmit -> ExecuteComplete");
                    }
                };

                //Submit the tracker to the task manager.
                payload.TraceWrite("Outgoing", "CommunicationContainer/PayloadSubmit");

                TaskSubmit(tracker);
            }
            catch (Exception ex)
            {
                Collector?.LogException($"ProcessClientPayload: unhandled error {payload.Source}/{payload.Message.CorrelationKey}-{payload} after {payload.Message?.FabricDeliveryCount} delivery attempts", ex);
                payload.TraceWrite($"Exception: {ex.Message}", "CommunicationContainer/PayloadSubmit");
                payload.SignalFail();
            }
        }
Beispiel #4
0
 /// <summary>
 /// This method injects a payload to be picked up by the polling algorithm.
 /// </summary>
 /// <param name="payload">The payload to inject.</param>
 public void Inject(TransmissionPayload payload)
 {
     try
     {
         mPending.Enqueue(payload);
         payload.TraceWrite("Enqueued", "ManualChannelClientHolder/Inject");
     }
     catch (Exception ex)
     {
         payload.TraceWrite($"Failed: {ex.Message}", "ManualChannelClientHolder/Inject");
     }
 }
Beispiel #5
0
        /// <summary>
        /// This method transmits the messages to the relevant senders.
        /// </summary>
        /// <param name="payload">The payload messages to externalOnly</param>
        public virtual async Task <bool> Send(TransmissionPayload payload)
        {
            payload.TraceConfigure(mPolicy.TransmissionPayloadTraceEnabled);
            payload.TraceWrite("Outgoing", "CommunicationContainer/Send");

            try
            {
                //Set outgoing routing information to lower case. This is important as messaging protocols such as
                //Service Bus can be case sensitive when running subscription filters.
                if (mPolicy.ServiceMessageHeaderConvertToLowercase)
                {
                    payload.Message.ConvertMessageHeadersToLowercase();
                }

                Channel channel = PayloadOutgoingRedirectChecks(payload);

                PayloadOutgoingSecurity(payload);

                //No, we want to send the message externally.
                List <ISender> messageSenders = null;
                //Get the supported message handler
                if (channel != null && !mMessageSenderMap.TryGetValue(channel.Id, out messageSenders))
                {
                    messageSenders = MessageSenderResolve(payload);
                }

                //If there are no supported senders for the particular channelId then throw an exception
                if (messageSenders == null || messageSenders.Count == 0)
                {
                    Collector?.LogMessage(LoggingLevel.Warning, string.Format("Unable to resolve sender for message {0}", payload != null ? payload.Message : null), "Communication");
                    payload.TraceWrite("Senders Unresolved", "CommunicationContainer/Send");
                    return(false);
                }

                //Set the outgoing originator if not set.
                if (string.IsNullOrEmpty(payload.Message.OriginatorServiceId))
                {
                    payload.Message.OriginatorServiceId = OriginatorId.ExternalServiceId;
                }

                //Send the message to the supported senders.
                await Task.WhenAll(messageSenders.Select(s => s.ProcessMessage(payload)));
            }
            catch (Exception ex)
            {
                Collector?.LogException(string.Format("Unable to send message {0}", payload != null ? payload.Message : null), ex);
                payload.TraceWrite($"Exception: {ex.Message}", "CommunicationContainer/Send");
                return(false);
            }

            return(true);
        }
Beispiel #6
0
        /// <summary>
        /// Purges any remaining messages when the service shuts down.
        /// </summary>
        public void Purge()
        {
            TransmissionPayload payload = null;

            while (mPending?.TryDequeue(out payload) ?? false)
            {
                payload.TraceWrite("Purged", "ManualChannelClientHolder/Purge");
                payload.SignalFail();
            }
        }
Beispiel #7
0
        /// <summary>
        /// This method separates the payloads so that they are different objects.
        /// </summary>
        /// <param name="inPayload">The incoming payload.</param>
        /// <param name="signal">The optional signal action.</param>
        /// <param name="traceEnabled">Specifies whether trace is enabled. If omitted or set to null, the value inherits from the incoming payload.</param>
        /// <returns>Returns a new cloned payload.</returns>
        public static TransmissionPayload Clone(this TransmissionPayload inPayload, Action <bool, Guid> signal, bool?traceEnabled = null)
        {
            traceEnabled = traceEnabled ?? inPayload.TraceEnabled;
            //First clone the service message.
            var cloned = new TransmissionPayload(inPayload.Message.Clone(), release: signal, traceEnabled: traceEnabled.Value);

            cloned.TraceWrite("Cloned", "ManualCommunicationBridgeAgent/PayloadCopy");

            return(cloned);
        }
        /// <summary>
        /// This method validates the payload with the security container.
        /// </summary>
        /// <param name="payload">The incoming payload.</param>
        protected virtual void PayloadPack(TransmissionPayload payload)
        {
            //Try and resolve the channel.
            Channel channel = null;

            TryGet(payload.Message.ChannelId, ChannelDirection.Outgoing, out channel);

            //Secure the outgoing payload.
            Secure(channel, payload);
            payload.TraceWrite("Secured", "CommunicationContainer/PayloadOutgoingSecurity");
        }
        /// <summary>
        /// This method validates the payload with the security container.
        /// </summary>
        /// <param name="payload">The incoming payload.</param>
        protected virtual void PayloadUnpack(TransmissionPayload payload)
        {
            //Try and resolve the channel.
            Channel channel = null;

            TryGet(payload.Message.ChannelId, ChannelDirection.Incoming, out channel);

            //Decrypt and verify the incoming message.
            Verify(channel, payload);
            payload.TraceWrite("Verified", "CommunicationContainer/PayloadIncomingSecurity");
        }
Beispiel #10
0
        /// <summary>
        /// This method injects a service message manually in to the Microservice.
        /// </summary>
        /// <param name="payload">The message payload.</param>
        /// <param name="priority">The optional priority. The default is 1.</param>
        public void Inject(TransmissionPayload payload, int?priority = null)
        {
            if (this.Status != ServiceStatus.Running)
            {
                payload.SignalSuccess();
                payload.TraceWrite($"Failed: {Status}", "ManualChannelListener/Inject");
                return;
            }

            try
            {
                var client = ClientResolve(priority ?? mDefaultPriority ?? 1);
                client.Inject(payload);
                payload.TraceWrite($"Success: {client.Name}", "ManualChannelListener/Inject");
            }
            catch (Exception ex)
            {
                payload.TraceWrite($"Error: {ex.Message}", "ManualChannelListener/Inject");
            }
        }
Beispiel #11
0
        /// <summary>
        /// This method injects a payload in to the execution path and bypasses the listener infrastructure.
        /// </summary>
        /// <param name="payload">The transmission payload to execute.</param>
        public virtual void Process(TransmissionPayload payload)
        {
            ValidateServiceStarted();

            if (mTransmissionPayloadTraceEnabled)
            {
                payload.TraceEnabled = true;
                payload.TraceWrite($"{Name} received.");
            }

            ExecuteOrEnqueue(payload, $"{Name} method request");
        }
Beispiel #12
0
        /// <summary>
        /// This method injects a payload in to the execution path and bypasses the listener infrastructure.
        /// </summary>
        /// <param name="payload">The transmission payload to execute.</param>
        public void Process(TransmissionPayload payload)
        {
            ValidateServiceStarted();

            if (mTransmissionPayloadTraceEnabled)
            {
                payload.TraceEnabled = true;
                payload.TraceWrite("howdy");
            }

            ExecuteOrEnqueue(payload, "Incoming Process method request");
        }
        /// <summary>
        /// Processes the request if self generated. This is used to accommodate state change.
        /// </summary>
        /// <param name="rq">The incoming request.</param>
        /// <returns>Returns true if the request is from this command.</returns>
        protected virtual bool ProcessRequestIfSelfGenerated(TransmissionPayload rq)
        {
            if (!string.Equals(rq.Message.OriginatorServiceId, OriginatorId.ExternalServiceId, StringComparison.InvariantCultureIgnoreCase))
            {
                return(false);
            }

            rq.TraceWrite("Processing", "Command/ProcessSelfSentMessage");
            switch (mMasterJobContext.State)
            {
            case MasterJobState.VerifyingComms:
                //We can now say that the masterjob channel is working, so we can now enable the job for negotiation.
                mMasterJobContext.State = MasterJobState.Starting;
                break;

            case MasterJobState.Inactive:
                if (mMasterJobContext.MasterPollAttemptsExceeded())
                {
                    mMasterJobContext.State = MasterJobState.Starting;
                }
                break;

            case MasterJobState.Starting:
                if (IsMatch(rq, MasterJobStates.WhoIsMaster) && mMasterJobContext.MasterPollAttemptsExceeded())
                {
                    mMasterJobContext.State = MasterJobState.Requesting1;
                }
                break;

            case MasterJobState.Requesting1:
                if (IsMatch(rq, MasterJobStates.RequestingControl1) && mMasterJobContext.MasterPollAttemptsExceeded())
                {
                    mMasterJobContext.State = MasterJobState.Requesting2;
                }
                break;

            case MasterJobState.Requesting2:
                if (IsMatch(rq, MasterJobStates.RequestingControl2) && mMasterJobContext.MasterPollAttemptsExceeded())
                {
                    mMasterJobContext.State = MasterJobState.TakingControl;
                }
                break;

            case MasterJobState.TakingControl:
                if (IsMatch(rq, MasterJobStates.TakingControl))
                {
                    MasterJobStart();
                }
                break;
            }

            return(true);
        }
Beispiel #14
0
        /// <summary>
        /// This method validates any rewrite rules for the incoming payload.
        /// </summary>
        /// <param name="payload">The incoming payload.</param>
        protected virtual void PayloadIncomingRedirectCheck(TransmissionPayload payload)
        {
            var channelId = payload.Message.ChannelId;
            //Rewrite rule validate, and rewrite for incoming message.
            Channel channel;

            if (TryGet(channelId, ChannelDirection.Incoming, out channel))
            {
                if (channel.CouldRedirect)
                {
                    channel.Redirect(payload);
                    payload.TraceWrite("Redirected", "CommunicationContainer/PayloadIncomingRedirectCheck");
                }
            }
        }
        /// <summary>
        /// This method injects a payload in to the execution path and bypasses the listener infrastructure.
        /// </summary>
        /// <param name="payload">The transmission payload to execute.</param>
        public override void Process(TransmissionPayload payload)
        {
            ValidateServiceStarted();

            if (payload.Message.OriginatorServiceId == null && DefaultOriginatorServiceId != null)
            {
                payload.Message.OriginatorServiceId = DefaultOriginatorServiceId;
            }

            if (mTransmissionPayloadTraceEnabled)
            {
                payload.TraceEnabled = true;
                payload.TraceWrite($"{Name} received.");
            }

            ExecuteOrEnqueue(payload, $"{Name} method request");
        }
Beispiel #16
0
        /// <summary>
        /// This helper method turns round an incoming payload request in to its corresponding response payload.
        /// </summary>
        /// <param name="incoming">The incoming payload.</param>
        /// <returns></returns>
        public static TransmissionPayload ToResponse(this TransmissionPayload incoming)
        {
            var m         = incoming.Message;
            var rsMessage = m.ToResponse();

            rsMessage.ChannelId       = m.ResponseChannelId;
            rsMessage.ChannelPriority = m.ResponseChannelPriority;
            rsMessage.MessageType     = m.ResponseMessageType;
            rsMessage.ActionType      = m.ResponseActionType;

            var outgoing = new TransmissionPayload(rsMessage, traceEnabled: incoming.TraceEnabled);

            if (incoming.TraceEnabled)
            {
                outgoing.TraceWrite(new TransmissionPayloadTraceEventArgs(outgoing.TickCount, "Created from request", "ToResponse"));
            }

            return(outgoing);
        }
Beispiel #17
0
        /// <summary>
        /// This method checks for any redirect rules for the outgoing payload.
        /// </summary>
        /// <param name="payload">The outgoing payload.</param>
        /// <returns>The outgoing channel.</returns>
        protected virtual Channel PayloadOutgoingRedirectChecks(TransmissionPayload payload)
        {
            //Rewrite rule validate, and rewrite for outgoing message.
            var     channelId = payload.Message.ChannelId;
            Channel channel;

            if (TryGet(channelId, ChannelDirection.Outgoing, out channel))
            {
                if (channel.CouldRedirect)
                {
                    channel.Redirect(payload);
                    payload.TraceWrite("Redirected", "CommunicationContainer/PayloadOutgoingRedirectChecks");

                    //Get the new outgoing channel.
                    TryGet(payload.Message.ChannelId, ChannelDirection.Outgoing, out channel);
                }
            }

            return(channel);
        }
Beispiel #18
0
        /// <summary>
        /// This method rewrites the rule.
        /// </summary>
        /// <param name="payload">The payload to adjust the incoming header information.</param>
        public void Redirect(TransmissionPayload payload)
        {
            var header = payload.Message.ToServiceMessageHeader();

            Guid?id = null;

            if (!mRedirectCache.ContainsKey(header))
            {
                id = RedirectBuildCacheEntry(header, payload);
            }
            else
            {
                id = mRedirectCache[header];
            }

            //There is an entry, but this may be null if there isn't a match.
            if (id.HasValue)
            {
                mRedirectRules[id.Value].Redirect(payload);
                payload.TraceWrite("Rule matched: {id.Value}", "Channel/Redirect");
            }

            return;
        }
        /// <summary>
        /// This method processes state notifications from other instances of the MasterJob.
        /// </summary>
        /// <param name="rq">The request.</param>
        /// <param name="rs">The responses - this is not used.</param>
        protected virtual async Task MasterJobStateNotificationIncoming(TransmissionPayload rq, List <TransmissionPayload> rs)
        {
            mMasterJobContext.NegotiationPollLastIn = DateTime.UtcNow;
            rq.TraceWrite("Received", "Command/MasterJobStateNotificationIncoming");

            //If we are not active then do nothing.
            if (mMasterJobContext.State == MasterJobState.Disabled)
            {
                return;
            }

            //Filter out the messages sent from this service.
            //We will use these messages to signal a transition to the next state.
            if (ProcessRequestIfSelfGenerated(rq))
            {
                return;
            }

            rq.TraceWrite("Processing", "Command/MasterJobStateNotificationIncoming");

            //Raise an event for the incoming communication.
            FireAndDecorateEventArgs(OnMasterJobCommunication, () => new MasterJobCommunicationEventArgs(
                                         MasterJobCommunicationDirection.Incoming
                                         , mMasterJobContext.State
                                         , rq.Message.ActionType
                                         , mMasterJobContext.StateChangeCounter
                                         , rq.Message.OriginatorServiceId));

            if (IsMatch(rq, MasterJobStates.IAmStandby))
            {
                mMasterJobContext.PartnerSet(rq.Message.OriginatorServiceId, true);
            }
            else if (IsMatch(rq, MasterJobStates.IAmMaster))
            {
                if (mMasterJobContext.State == MasterJobState.Active)
                {
                    MasterJobStop();
                }

                mMasterJobContext.PartnerSet(rq.Message.OriginatorServiceId, false);

                mMasterJobContext.State = MasterJobState.Inactive;

                await NegotiationTransmit(MasterJobStates.IAmStandby);
            }
            else if (IsMatch(rq, MasterJobStates.ResyncMaster))
            {
                mMasterJobContext.PartnerMasterClear();

                if (mMasterJobContext.State == MasterJobState.Inactive)
                {
                    mMasterJobContext.State = MasterJobState.Starting;
                }
            }
            else if (IsMatch(rq, MasterJobStates.WhoIsMaster))
            {
                mMasterJobContext.PartnerSet(rq.Message.OriginatorServiceId, true);
                if (mMasterJobContext.State == MasterJobState.Active)
                {
                    await MasterJobSyncIAmMaster();
                }
            }
            else if (IsMatch(rq, MasterJobStates.RequestingControl1))
            {
                await InformOrResetState(MasterJobState.Requesting1);
            }
            else if (IsMatch(rq, MasterJobStates.RequestingControl2))
            {
                await InformOrResetState(MasterJobState.Requesting2);
            }
            else if (IsMatch(rq, MasterJobStates.TakingControl))
            {
                await InformOrResetState(MasterJobState.TakingControl);
            }
            else
            {
                Collector?.LogMessage(LoggingLevel.Warning, $"{rq?.Message?.ActionType??"NULL"} is not a valid negotiating action type for master job {FriendlyName}", "MasterJob");
                rq.TraceWrite("Unhandled", "Command/MasterJobStateNotificationIncoming");
                return;
            }
            rq.TraceWrite("Complete", "Command/MasterJobStateNotificationIncoming");
        }