/// <summary> /// Processes the exception. /// </summary> /// <param name="ex">The exception raised.</param> /// <param name="rq">The incoming request.</param> /// <param name="responses">The responses.</param> protected virtual Task ProcessRequestException(Exception ex, TransmissionPayload rq, List <TransmissionPayload> responses) { if (mPolicy.OnProcessRequestExceptionLog) { Collector?.LogException($"{FriendlyName}/ProcessRequest unhandled exception: {rq.Message.ToKey()}", ex); } switch (mPolicy.OnProcessRequestException) { case ProcessRequestExceptionBehaviour.DoNothing: break; case ProcessRequestExceptionBehaviour.SignalSuccessAndSend500ErrorResponse: rq.SignalSuccess(); var rs = rq.ToResponse(); rs.Message.Status = "500"; rs.Message.StatusDescription = ex.Message; responses.Add(rs); break; case ProcessRequestExceptionBehaviour.SignalFailAndDoNothing: rq.SignalFail(); break; default: throw ex; } return(Task.FromResult(0)); }
/// <summary> /// This method is called to process an incoming payload. /// </summary> /// <param name="rq">The message to process.</param> /// <param name="responses">The return path for the message.</param> public virtual async Task ProcessRequest(TransmissionPayload rq, List <TransmissionPayload> responses) { var header = rq.Message.ToServiceMessageHeader(); H handler; if (!SupportedResolve(header, out handler)) { var ex = new CommandNotSupportedException(rq.Id, header, GetType()); FireAndDecorateEventArgs(OnRequestUnresolved, () => new ProcessRequestEventArgs(rq, ex)); throw ex; } FireAndDecorateEventArgs(OnRequest, () => new ProcessRequestEventArgs(rq)); int start = StatisticsInternal.ActiveIncrement(); try { //Call the registered command. This should not throw an exception if a hander has been registered. await handler.Execute(rq, responses); } catch (Exception ex) { StatisticsInternal.ErrorIncrement(); FireAndDecorateEventArgs(OnRequestUnhandledException, () => new ProcessRequestEventArgs(rq, ex)); //Handler has not caught the exception, so we default to the default policy behaviour. await ProcessRequestException(ex, rq, responses); } finally { StatisticsInternal.ActiveDecrement(start); } }
/// <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; H client = null; try { client = ClientResolve(payload.Message.ChannelPriority); start = client.StatisticsInternal.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.StatisticsInternal.ErrorIncrement(); } throw; } finally { if (client != null && start.HasValue) { client.StatisticsInternal.ActiveDecrement(start.Value); } } }
private void Sender_TransmitBroadcast(TransmissionPayload e, long count) { for (int c = 0; c < mListeners.Count; c++) { mListeners[c].Inject(PayloadCopy(e)); } }
/// <summary> /// This method is called to process an incoming payload. /// </summary> /// <param name="rq">The message to process.</param> /// <param name="responses">The return path for the message.</param> public virtual async Task ProcessRequest(TransmissionPayload rq, List <TransmissionPayload> responses) { int start = StatisticsInternal.ActiveIncrement(); try { var header = rq.Message.ToServiceMessageHeader(); H handler; if (!SupportedResolve(header, out handler)) { OnRequestUnresolved?.Invoke(this, rq); throw new CommandNotSupportedException(rq.Id, header, GetType()); } OnRequest?.Invoke(this, rq); //Call the registered command. await handler.Execute(rq, responses); } catch (Exception) { StatisticsInternal.ErrorIncrement(); //throw any errors back out to the dispatcher. throw; } finally { StatisticsInternal.ActiveDecrement(start); } }
/// <summary> /// This method packs the ServiceMessage in to the BrokeredMessage format /// for communication through the Azure Service Bus. /// </summary> /// <param name="payload">The payload to convert.</param> /// <returns>Returns a converted BrokeredMessage from transmission.</returns> public BrokeredMessage PackEventSource(TransmissionPayload payload) { var entry = payload.MessageObject as EventSourceEntryBase; byte[] blob; using (var stream = new MemoryStream()) using (var streamWriter = new StreamWriter(stream)) using (var textWriter = new JsonTextWriter(streamWriter)) { mJsonSerializer.Serialize(textWriter, payload.MessageObject); streamWriter.Flush(); stream.Position = 0; blob = stream.ToArray(); } BrokeredMessage bMessage = new BrokeredMessage(blob); bMessage.Properties.Add("BatchId", entry.BatchId); bMessage.Properties.Add("CorrelationId", entry.CorrelationId); bMessage.Properties.Add("Key", entry.Key); bMessage.Properties.Add("EntityType", entry.EntityType); bMessage.Properties.Add("EntityVersion", entry.EntityVersion); bMessage.Properties.Add("UTCTimeStamp", entry.UTCTimeStamp); bMessage.Properties.Add("OriginatorId", OriginatorId); return(bMessage); }
/// <summary> /// This is the default constructor. /// </summary> /// <param name="rq">The incoming request.</param> /// <param name="rsCol">The outgoing response collection.</param> /// <param name="serializer">The serialization container.</param> /// <param name="collector">The data collector.</param> /// <param name="sharedServices">The shared service context.</param> /// <param name="originatorId">This is the Microservice identifiers.</param> /// <param name="outgoingRequest">This is the outgoing request initiator.</param> public CommandMethodRequestContext(TransmissionPayload rq, List <TransmissionPayload> rsCol , IPayloadSerializationContainer serializer , IDataCollection collector , ISharedService sharedServices , MicroserviceId originatorId , ICommandOutgoing outgoingRequest) : base(rq, rsCol, serializer, collector, sharedServices, originatorId, outgoingRequest) { }
public OutgoingRequestTracker(string id, TransmissionPayload payload, TimeSpan ttl, int?start = null) { Id = id; Payload = payload; Tcs = new TaskCompletionSource <TransmissionPayload>(); Start = start ?? Environment.TickCount; MaxTTL = ttl; }
private void Sender_TransmitRoundRobin(TransmissionPayload e, long count) { var listeners = mActiveListeners; int position = (int)(count % listeners.Length); Sender_Transmit(listeners[position], e); }
/// <summary> /// This extension method is used to set the response for an inline message. /// </summary> /// <param name="c">The incoming context.</param> /// <param name="status">The response status.</param> /// <param name="description">The optional response description</param> public static void ResponseSet(this CommandMethodInlineContext c, int status, string description = null) { TransmissionPayload ars = c.Request.ToResponse(); ars.Message.StatusSet(status, description); c.Responses.Add(ars); }
/// <summary> /// This is the default constructor. /// </summary> /// <param name="rq">The incoming request.</param> /// <param name="rsCol">The outgoing response collection.</param> /// <param name="serializer">The serialization container.</param> /// <param name="collector">The data collector.</param> /// <param name="sharedServices">The shared service context.</param> /// <param name="originatorId">This is the Microservice identifiers.</param> public CommandMethodInlineContext(TransmissionPayload rq, List <TransmissionPayload> rsCol , IPayloadSerializationContainer serializer , IDataCollection collector , ISharedService sharedServices , MicroserviceId originatorId) : base(serializer, collector, sharedServices, originatorId) { Request = rq; Responses = rsCol; }
/// <summary> /// This method injects a service message in to the execution path and bypasses the listener infrastructure. /// </summary> /// <param name="message">The service message.</param> /// <param name="options">The process options.</param> /// <param name="release">The release action which is called when the payload has been executed.</param> /// <param name="isDeadLetterMessage">A flag indicating whether the message is a deadletter replay. These messages may be treated differently /// by the receiving commands.</param> public void Process(ServiceMessage message , ProcessOptions options = ProcessOptions.RouteExternal | ProcessOptions.RouteInternal , Action <bool, Guid> release = null , bool isDeadLetterMessage = false) { var payload = new TransmissionPayload(message, release: release, options: options, isDeadLetterMessage: isDeadLetterMessage); Process(payload); }
/// <summary> /// This method seperates the payloads so that they are different objects. /// </summary> /// <param name="inPayload">The incoming payload.</param> /// <returns>Returns a new payload.</returns> private TransmissionPayload PayloadCopy(TransmissionPayload inPayload) { //First clone the service message. byte[] data = mSerializer.Serialize(inPayload.Message); ServiceMessage clone = mSerializer.Deserialize <ServiceMessage>(data); return(new TransmissionPayload(clone)); }
protected virtual TimeSpan DefaultDelayBetweenRetries(TransmissionPayload transmissionPayload, int i) { if (transmissionPayload != null && transmissionPayload.Message != null && transmissionPayload.Message.ChannelPriority == 0) { return(TimeSpan.FromMilliseconds(i * 10)); } return(TimeSpan.FromSeconds(i)); }
/// <summary> /// This method sends a message to the underlying dispatcher and tracks its progress. /// </summary> /// <typeparam name="K"></typeparam> /// <param name="payloadRq">The payload to process.</param> /// <param name="processResponse"></param> /// <param name="processAsync">Specifies whether the process in async in which case it is /// returned immediately without waiting for the payload to be processed.</param> /// <returns>The task with a payload of type K</returns> protected async Task <K> OutgoingRequestOut <K>(TransmissionPayload payloadRq, Func <TaskStatus, TransmissionPayload, bool, K> processResponse, bool processAsync = false) { ValidateServiceStarted(); if (payloadRq == null) { throw new ArgumentNullException("payloadRequest has not been set."); } if (processResponse == null) { throw new ArgumentNullException("processPayload has not been set."); } //Create and register the request holder. var tracker = new OutgoingRequestTracker(payloadRq, payloadRq.MaxProcessingTime ?? Policy.OutgoingRequestMaxProcessingTimeDefault); //Add the outgoing holder to the collection if (!mOutgoingRequests.TryAdd(tracker.Id, tracker)) { var errorStr = $"OutgoingRequestTransmit: Duplicate key {tracker.Id}"; Collector?.LogMessage(LoggingLevel.Error, errorStr, "RqDuplicate"); throw new OutgoingRequestTransmitException(errorStr); } //Raise the event. FireAndDecorateEventArgs(OnOutgoingRequest, () => new OutgoingRequestEventArgs(tracker)); //Submit the payload for processing to the task manager TaskManager(this, tracker.Id, tracker.Payload); //OK, this is a sync process, let's wait until it responds or times out. TransmissionPayload payloadRs = null; //This has not been marked async so hold the current task until completion. if (!processAsync) { try { if (UseASPNETThreadModel) { payloadRs = Task.Run(async() => await tracker.Tcs.Task).Result; } else { payloadRs = await tracker.Tcs.Task; } } catch (Exception) { } } return(processResponse(tracker.Tcs.Task.Status, payloadRs, processAsync)); }
/// <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> /// 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(); } }
/// <summary> /// This method validates the payload with the security container. /// </summary> /// <param name="payload">The incoming payload.</param> protected virtual void PayloadOutgoingSecurity(TransmissionPayload payload) { //Try and resolve the channel. Channel channel = null; TryGet(payload.Message.ChannelId, ChannelDirection.Outgoing, out channel); //Secure the outgoing payload. Security.Secure(channel, payload); }
/// <summary> /// This method validates the payload with the security container. /// </summary> /// <param name="payload">The incoming payload.</param> protected virtual void PayloadIncomingSecurity(TransmissionPayload payload) { //Try and resolve the channel. Channel channel = null; TryGet(payload.Message.ChannelId, ChannelDirection.Incoming, out channel); //Decrypt and verify the incoming message. Security.Verify(channel, payload); }
/// <summary> /// This is the default constructor. /// </summary> /// <param name="rq">The incoming request.</param> /// <param name="rsCol">The outgoing response collection.</param> /// <param name="serviceHandlers">The service handlers container.</param> /// <param name="collector">The data collector.</param> /// <param name="sharedServices">The shared service context.</param> /// <param name="originatorId">This is the Microservice identifiers.</param> /// <param name="outgoingRequest">This is the outgoing request initiator.</param> public CommandRequestContextBase(TransmissionPayload rq, List <TransmissionPayload> rsCol , IServiceHandlers serviceHandlers , IDataCollection collector , ISharedService sharedServices , MicroserviceId originatorId , O outgoingRequest) : base(serviceHandlers, collector, sharedServices, originatorId, outgoingRequest) { Request = rq; Responses = rsCol; }
protected virtual int DefaultMaximumRetries(TransmissionPayload transmissionPayload) { // Channel 0 async processing should keep retrying if (transmissionPayload != null && transmissionPayload.Message != null && transmissionPayload.Message.ChannelPriority == 0) { return(500); } return(5); }
/// <summary> /// This method marshalls the incoming requests from the Initiators. /// </summary> /// <param name="caller">The caller.</param> /// <param name="message">The message to process.</param> public virtual R ProcessMessage(IService caller, TransmissionPayload payload) { //Create and register the request holder. var holder = HolderCreate(caller, payload); Register(holder); ProcessMessageInternal(holder); return(holder); }
/// <summary> /// This method is called when a command throws an unhanlded exception when processing the request /// </summary> /// <param name="payload">The request payload.</param> /// <param name="pex">The unhandled exception.</param> internal virtual void OnProcessRequestError(TransmissionPayload payload, Exception pex) { try { ProcessRequestError?.Invoke(this, new ProcessRequestErrorEventArgs(payload, pex)); } catch (Exception ex) { mDataCollection?.LogException("ProcessRequestError event / external exception thrown on event", ex); } }
/// <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 formats the key used to hold the priority processes. /// </summary> /// <param name="caller">The calling object.</param> /// <returns>Returns a formatted string containing both parts.</returns> protected virtual string Key(IService caller, TransmissionPayload payload) { if (mKeyMaker != null) { return(mKeyMaker(caller, payload)); } string type = caller == null ? "" : caller.GetType().Name; return(string.Format("{0}|{1}", type, Guid.NewGuid().ToString("N")).ToLowerInvariant()); }
/// <summary> /// This method injects a service message in to the execution path and bypasses the listener infrastructure. /// </summary> /// <param name="dispatcher">The Microservice dispatcher.</param> /// <param name="message">The service message.</param> /// <param name="options">The process options.</param> /// <param name="release">The release action which is called when the payload has been executed by the receiving commands.</param> public static void Process(this IMicroserviceDispatch dispatcher , ServiceMessage message , ProcessOptions options = ProcessOptions.RouteExternal | ProcessOptions.RouteInternal , Action <bool, Guid> release = null) { var payload = new TransmissionPayload(message , release: release , options: options); dispatcher.Process(payload); }
private void ProcessInvoke(TransmissionPayload payload) { try { OnProcess?.Invoke(this, payload); } catch (Exception ex) { Collector?.LogException("ManualChannelSender/ProcessInvoke", ex); } }
/// <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"); }
public PersistenceRequestHolder(Guid profileId, TransmissionPayload prq, List <TransmissionPayload> prs) { this.ProfileId = profileId; this.Prq = prq; this.Prs = prs; Start = Environment.TickCount; result = null; Rq = null; Rs = null; }
/// <summary> /// This message resolves the specific handler that can process the incoming message. /// </summary> /// <param name="payload">The incoming message payload.</param> /// <returns>Returns the supported handlers or null.</returns> protected virtual List <ISender> MessageSenderResolve(TransmissionPayload payload) { var message = payload.Message; string channelId = message.ChannelId; List <ISender> newMap = mSenders.Where(h => h.SupportsChannel(channelId)).ToList(); //Make sure that the handler is queueAdded as a null value to stop further resolution attempts mMessageSenderMap.AddOrUpdate(channelId, newMap, (k, u) => newMap.Count == 0 ? null : newMap); return(newMap); }