/// <summary> /// This method writes the incoming event data to the data collectors. /// </summary> /// <param name="eventData">The event data.</param> /// <param name="support">The event data type.</param> /// <param name="sync">Specifies whether the data should be written out immediately.</param> /// <param name="claims">The optional claims of the calling party. If not set explicitly, then this /// will be populated from the current thread. If you don't want this then pass an empty claims object.</param> public void Write(EventBase eventData, DataCollectionSupport support, bool sync = false, ClaimsPrincipal claims = null) { if (eventData == null) { throw new ArgumentNullException("eventData", "eventData cannot be null for Write"); } if (!Active) { throw new ServiceNotStartedException(); } //Create the event holder and set the identity based on the claims passed or if null, //picked up from the current thread. var item = new EventHolder(support, claims ?? Thread.CurrentPrincipal as ClaimsPrincipal) { Data = eventData , Sync = sync , Timestamp = StatisticsInternal.ActiveIncrement() }; //Do we have to write this straight away, or can we push it on to an async thread. if (item.Sync) { //Process the item immediately. ProcessItem(item); } else { mQueue.Enqueue(item); //Signal to the logging thread that there is more data waiting. mReset.Set(); } }
/// <summary> /// This method marshals the RepositoryHolder and transmits it to the remote Microservice. /// </summary> /// <typeparam Name="KT">The key type.</typeparam> /// <typeparam Name="ET">The entity type.</typeparam> /// <param name="actionType">The action type.</param> /// <param name="rq">The repository holder request.</param> /// <param name="routing"></param> /// <returns>Returns an async task that will be signalled when the request completes or times out.</returns> protected override async Task <RepositoryHolder <KT, ET> > TransmitInternal <KT, ET>(string actionType, RepositoryHolder <KT, ET> rq, ProcessOptions?routing = null, IPrincipal principal = null) { StatisticsInternal.ActiveIncrement(); var payloadRq = TransmissionPayload.Create(mPolicy.TransmissionPayloadTraceEnabled); // Set the originator key to the correlation id if passed through the rq settings if (!string.IsNullOrEmpty(rq.Settings?.CorrelationId)) { payloadRq.Message.ProcessCorrelationKey = rq.Settings.CorrelationId; } bool processAsync = rq.Settings?.ProcessAsync ?? false; payloadRq.Options = ProcessOptions.RouteInternal; var message = payloadRq.Message; payloadRq.MaxProcessingTime = rq.Settings?.WaitTime ?? mDefaultRequestTimespan; payloadRq.MessageObject = rq; message.ChannelId = ChannelId; message.ChannelPriority = processAsync ? 0:-1; message.MessageType = mMessageType; message.ActionType = actionType; message.ResponseChannelId = mResponseChannel; message.ResponseChannelPriority = -1; //Always internal message.Blob = PayloadSerializer.PayloadSerialize(rq); return(await OutgoingRequestOut(payloadRq, ProcessResponse <KT, ET>, processAsync : processAsync)); }
protected async Task Output(string id, string directory, byte[] blob, string contentType, string contentEncoding = null) { int start = StatisticsInternal.ActiveIncrement(); Guid traceId = ProfileStart(id, directory); var result = ResourceRequestResult.Unknown; try { await mStorage.CreateOrUpdate(id, blob , directory : directory , contentType : contentType , contentEncoding : contentEncoding , createSnapshot : false); result = ResourceRequestResult.Success; } catch (StorageThrottlingException) { result = ResourceRequestResult.Exception; throw; } catch (Exception ex) { result = ResourceRequestResult.Exception; Collector?.LogException(string.Format("Unable to output {0} to {1} for {2}", id, directory, contentType), ex); StatisticsInternal.ErrorIncrement(); throw; } finally { ProfileEnd(traceId, start, result); StatisticsInternal.ActiveDecrement(start); } }
/// <summary> /// This method will write the current items in the queue to the stream processor. /// </summary> protected virtual int ProcessQueue(int?timespaninms = null) { ActionQueueContainer <D> logEvent; DateTime start = DateTime.UtcNow; int items = 0; do { while (mQueue.TryDequeue(out logEvent)) { EventWrite(logEvent.Data); items++; StatisticsInternal.ActiveDecrement(logEvent.Timestamp); //Kick out every 100 loops if there is a timer limit. if (timespaninms.HasValue && (items % 100 == 0)) { break; } } }while (mQueue.Count > 0 && (!timespaninms.HasValue || (DateTime.UtcNow - start).TotalMilliseconds < timespaninms)); return(items); }
/// <summary> /// This method is called to process an incoming message. /// </summary> /// <param name="request">The message to process.</param> /// <param name="responses">The return path for the message.</param> public virtual async Task ProcessMessage(TransmissionPayload requestPayload, List <TransmissionPayload> responses) { int start = StatisticsInternal.ActiveIncrement(); try { var header = requestPayload.Message.ToServiceMessageHeader(); H handler; if (!SupportedResolve(header, out handler)) { throw new NotSupportedException(string.Format("This command is not supported: '{0}' in {1}", header, GetType().Name)); } //Call the registered command. await handler.Execute(requestPayload, responses); } catch (Exception) { StatisticsInternal.ErrorIncrement(); throw; } finally { StatisticsInternal.ActiveDecrement(start); } }
/// <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 marshals the RepositoryHolder and transmits it to the remote Microservice. /// </summary> /// <typeparam Name="KT">The key type.</typeparam> /// <typeparam Name="ET">The entity type.</typeparam> /// <param name="actionType">The action type.</param> /// <param name="rq">The repository holder request.</param> /// <param name="routing"></param> /// <returns>Returns an async task that will be signalled when the request completes or times out.</returns> protected override async Task <RepositoryHolder <KT, ET> > TransmitInternal <KT, ET>(string actionType, RepositoryHolder <KT, ET> rq, ProcessOptions?routing = null) { StatisticsInternal.ActiveIncrement(); var payloadRq = TransmissionPayload.Create(); bool processAsync = rq.Settings?.ProcessAsync ?? false; payloadRq.Options = ProcessOptions.RouteInternal; var message = payloadRq.Message; payloadRq.MaxProcessingTime = rq.Settings?.WaitTime ?? mDefaultRequestTimespan; payloadRq.MessageObject = rq; message.ChannelId = ChannelId; message.ChannelPriority = processAsync ? 0:-1; message.MessageType = mMessageType; message.ActionType = actionType; message.ResponseChannelId = mResponseChannel; message.ResponseChannelPriority = -1; //Always internal message.Blob = PayloadSerializer.PayloadSerialize(rq); return(await TransmitAsync(payloadRq, ProcessResponse <KT, ET>, processAsync : processAsync)); }
/// <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 writes the event data to the underlying storage. /// </summary> /// <param name="connector">The generic connector.</param> /// <param name="e">The event to write.</param> /// <returns>This is an async process.</returns> protected virtual async Task WriteConnector(IAzureStorageConnectorBase connector, EventHolder e) { int start = StatisticsInternal.ActiveIncrement(connector.Support); Guid?traceId = connector.Options.ShouldProfile ? (ProfileStart($"Azure{connector.Support}_{e.Data.TraceId}")) : default(Guid?); var result = ResourceRequestResult.Unknown; try { await connector.Write(e, OriginatorId); result = ResourceRequestResult.Success; } catch (StorageThrottlingException) { result = ResourceRequestResult.Exception; throw; } catch (Exception ex) { result = ResourceRequestResult.Exception; //Collector?.LogException(string.Format("Unable to output {0} to {1} for {2}", id, directory, typeof(E).Name), ex); StatisticsInternal.ErrorIncrement(connector.Support); throw; } finally { StatisticsInternal.ActiveDecrement(connector.Support, start); if (traceId.HasValue) { ProfileEnd(traceId.Value, start, result); } } }
/// <summary> /// This is called when the request is retried due to an underlying storage issue. /// </summary> /// <typeparam name="KT">The key type.</typeparam> /// <typeparam name="ET">The entity type.</typeparam> /// <param name="holder">The request holder.</param> /// <param name="retryStart">The tick count of the retry point.</param> protected virtual void ProfileRetry <KT, ET>(PersistenceRequestHolder <KT, ET> holder, int retryStart) { mPolicy.ResourceConsumer?.Retry(holder.ProfileId, retryStart, holder.Rs.ShouldRetry ? ResourceRetryReason.Other : ResourceRetryReason.Timeout); holder.Retry(retryStart); StatisticsInternal.RetryIncrement(); }
/// <summary> /// This method processes the incoming event by looping through the collectors for the particular type. /// </summary> /// <param name="eventData">The event data holder.</param> protected void ProcessItem(EventHolder eventData) { mCollectorSupported[eventData.DataType]? .ForEach((l) => ProcessItem(l, eventData)); //Decrement the active count with the time needed to process. StatisticsInternal.ActiveDecrement(eventData.Timestamp); }
/// <summary> /// This method is used to process the returning message response. /// </summary> /// <typeparam name="KT"></typeparam> /// <typeparam name="ET"></typeparam> /// <param name="rType"></param> /// <param name="payload"></param> /// <param name="processAsync"></param> /// <returns></returns> protected virtual RepositoryHolder <KT, ET> ProcessResponse <KT, ET>(TaskStatus rType, TransmissionPayload payload, bool processAsync) { StatisticsInternal.ActiveDecrement(payload != null ? payload.Extent : TimeSpan.Zero); if (processAsync) { return(new RepositoryHolder <KT, ET>(responseCode: 202, responseMessage: "Accepted")); } try { switch (rType) { case TaskStatus.RanToCompletion: if (payload.MessageObject != null) { return(payload.MessageObject as RepositoryHolder <KT, ET>); } if (payload.Message.Blob == null) { return(new RepositoryHolder <KT, ET>(responseCode: 500, responseMessage: "Unexpected response (no payload)")); } try { var response = PayloadSerializer.PayloadDeserialize <RepositoryHolder <KT, ET> >(payload); return(response); } catch (Exception ex) { StatisticsInternal.ErrorIncrement(); return(new RepositoryHolder <KT, ET>(responseCode: 500, responseMessage: ex.Message)); } case TaskStatus.Canceled: StatisticsInternal.ErrorIncrement(); return(new RepositoryHolder <KT, ET>(responseCode: 408, responseMessage: "Time out")); case TaskStatus.Faulted: StatisticsInternal.ErrorIncrement(); return(new RepositoryHolder <KT, ET>() { ResponseCode = (int)PersistenceResponse.GatewayTimeout504, ResponseMessage = "Response timeout." }); default: StatisticsInternal.ErrorIncrement(); return(new RepositoryHolder <KT, ET>(responseCode: 500, responseMessage: rType.ToString())); } } catch (Exception ex) { Logger.LogException("Error processing response for task status " + rType, ex); throw; } }
/// <summary> /// This method enqueues the message. /// </summary> /// <param name="item">The task tracker to enqueue.</param> public void Enqueue(TaskTracker item) { var wrapper = new QueueTrackerHolder { Item = item, Ingress = StatisticsInternal.ActiveIncrement() }; mQueue.Enqueue(wrapper); StatisticsInternal.WaitingSet(Count); }
/// <summary> /// This method is the default method used to process the returning message response. /// </summary> /// <typeparam name="RS">The response type.</typeparam> /// <param name="rType"></param> /// <param name="payloadRs">The incoming response payload.</param> /// <param name="processAsync"></param> /// <returns>Returns the response wrapper generic object.</returns> protected virtual ResponseWrapper <RS> ProcessOutgoingResponse <RS>(TaskStatus rType, TransmissionPayload payloadRs, bool processAsync) { StatisticsInternal.ActiveDecrement(payloadRs?.Extent ?? TimeSpan.Zero); if (processAsync) { return(new ResponseWrapper <RS>(responseCode: 202, responseMessage: "Accepted")); } try { payloadRs?.CompleteSet(); switch (rType) { case TaskStatus.RanToCompletion: try { //payload.Message. var response = new ResponseWrapper <RS>(payloadRs); if (payloadRs.Message.Blob.HasObject) { response.Response = (RS)payloadRs.Message.Blob.Object; } else if (payloadRs.Message.Blob != null) { response.Response = PayloadSerializer.PayloadDeserialize <RS>(payloadRs); } return(response); } catch (Exception ex) { StatisticsInternal.ErrorIncrement(); return(new ResponseWrapper <RS>(500, ex.Message)); } case TaskStatus.Canceled: StatisticsInternal.ErrorIncrement(); return(new ResponseWrapper <RS>(408, "Time out")); case TaskStatus.Faulted: StatisticsInternal.ErrorIncrement(); return(new ResponseWrapper <RS>((int)PersistenceResponse.GatewayTimeout504, "Response timeout.")); default: StatisticsInternal.ErrorIncrement(); return(new ResponseWrapper <RS>(500, rType.ToString())); } } catch (Exception ex) { Collector?.LogException("Error processing response for task status " + rType, ex); throw; } }
/// <summary> /// This is wrapper class that provides generic exception handling support /// and retrieves the standard metadata for each request. /// </summary> /// <param name="rq">The request.</param> /// <param name="rs">The response.</param> /// <param name="action">The async action task.</param> /// <returns>Returns a task with the response.</returns> protected async Task <StorageResponseHolder> CallCloudBlockBlob(StorageRequestHolder rq , Func <StorageRequestHolder, StorageResponseHolder, bool, Task> action) { int start = StatisticsInternal.ActiveIncrement(); var rs = new StorageResponseHolder(); try { var refEntityDirectory = mEntityContainer.GetDirectoryReference(rq.Directory); rq.Blob = refEntityDirectory.GetBlockBlobReference(rq.SafeKey); bool exists = await rq.Blob.ExistsAsync(rq.CancelSet); if (exists) { MetadataGet(rq.Blob, rq); exists ^= rq.IsDeleted; } await action(rq, rs, exists); } catch (StorageException sex) { rs.Ex = sex; rs.IsSuccess = false; rs.StatusCode = sex.RequestInformation.HttpStatusCode; rs.IsTimeout = rs.StatusCode == 500 || rs.StatusCode == 503; } catch (TaskCanceledException tcex) { rs.Ex = tcex; rs.IsTimeout = true; rs.IsSuccess = false; rs.StatusCode = 502; } catch (Exception ex) { rs.Ex = ex; rs.IsSuccess = false; rs.StatusCode = 500; } finally { if (!rs.IsSuccess) { StatisticsInternal.ErrorIncrement(); } StatisticsInternal.ActiveDecrement(start); } return(rs); }
/// <summary> /// This method wraps the individual request in a safe wrapper. /// </summary> /// <param name="eventData">The event data.</param> /// <param name="item">The item to process.</param> protected virtual void ProcessItem(D eventData, I item) { try { Process(eventData, item); } catch (Exception ex) { //We don't want unexpected exceptions here and to stop the other loggers working. StatisticsInternal.ErrorIncrement(); StatisticsInternal.Ex = ex; } }
/// <summary> /// This method attemps to dequeue a message. /// </summary> /// <param name="item">The item dequeued or null</param> /// <returns>Returns true if a message was dequeued successfully.</returns> public bool TryDequeue(out TaskTracker item) { item = null; QueueTrackerHolder wrapper; if (mQueue.TryDequeue(out wrapper)) { item = wrapper.Item; StatisticsInternal.ActiveDecrement(wrapper.Ingress); return(true); } return(false); }
/// <summary> /// This method wraps the individual request in a safe wrapper. /// </summary> /// <param name="dataCollector">The data collector component.</param> /// <param name="eventData">The event data holder.</param> protected virtual void ProcessItem(IDataCollectorComponent dataCollector, EventHolder eventData) { try { dataCollector.Write(eventData); } catch (Exception ex) { //We don't want unexpected exceptions here and to stop the other loggers working. StatisticsInternal.ErrorIncrement(); StatisticsInternal.Ex = ex; } }
public bool TryDequeue(out TaskTracker item) { item = null; KeyValuePair <TaskTracker, int> wrapper; if (mQueue.TryDequeue(out wrapper)) { item = wrapper.Key; StatisticsInternal.ActiveDecrement(wrapper.Value); return(true); } return(false); }
/// <summary> /// This method marshals the RepositoryHolder and transmits it to the remote Microservice. /// </summary> /// <typeparam Name="KT">The key type.</typeparam> /// <typeparam Name="ET">The entity type.</typeparam> /// <param Name="actionType">The action type.</param> /// <param Name="rq">The repository holder request.</param> /// <returns>Returns an async task that will be signalled when the request completes or times out.</returns> protected override async Task <RepositoryHolder <KT, ET> > TransmitInternal <KT, ET>( string actionType, RepositoryHolder <KT, ET> rq, ProcessOptions?routing = null, IPrincipal principal = null) { try { StatisticsInternal.ActiveIncrement(); var payload = TransmissionPayload.Create(Policy.TransmissionPayloadTraceEnabled); payload.SecurityPrincipal = TransmissionPayload.ConvertToClaimsPrincipal(principal ?? Thread.CurrentPrincipal); // Set the process correlation key to the correlation id if passed through the rq settings if (!string.IsNullOrEmpty(rq.Settings?.CorrelationId)) { payload.Message.ProcessCorrelationKey = rq.Settings.CorrelationId; } bool processAsync = rq.Settings?.ProcessAsync ?? false; payload.Message.ChannelPriority = processAsync ? 0 : 1; payload.Options = routing ?? RoutingDefault ?? ProcessOptions.RouteExternal; payload.Message.Blob = PayloadSerializer.PayloadSerialize(rq); payload.Message.ResponseChannelId = ResponseChannelId; payload.Message.ResponseChannelId = ResponseId.Header.ChannelId; payload.Message.ResponseMessageType = ResponseId.Header.MessageType; payload.Message.ResponseActionType = ResponseId.Header.ActionType; payload.Message.ResponseChannelPriority = payload.Message.ChannelPriority; payload.Message.ChannelId = ChannelId; payload.Message.MessageType = EntityType; payload.Message.ActionType = actionType; payload.MaxProcessingTime = rq.Settings?.WaitTime ?? mDefaultRequestTimespan; return(await OutgoingRequestOut(payload, ProcessResponse <KT, ET>, processAsync)); } catch (Exception ex) { string key = rq != null && rq.Key != null?rq.Key.ToString() : string.Empty; Collector?.LogException($"Error transmitting {actionType}-{key} internally", ex); throw; } }
/// <summary> /// This method queues the incoming event data to be processed on the queue thread. /// </summary> /// <param name="eventData">The incoming event</param> protected virtual void EventEnqueue(D eventData) { if (!Active) { throw new ServiceNotStartedException(); } var item = new ActionQueueContainer <D> { Data = eventData, Timestamp = StatisticsInternal.ActiveIncrement() }; mQueue.Enqueue(item); mReset.Set(); }
/// <summary> /// Write event source /// </summary> /// <param name="support"></param> /// <param name="eventHolder"></param> protected virtual void WriteEvent(DataCollectionSupport support, EventHolder eventHolder) { var options = mPolicy.Options.FirstOrDefault(o => o.Support == support); if (options == null || !options.IsSupported(eventHolder)) { return; } int start = StatisticsInternal.ActiveIncrement(options.Support); Guid?traceId = options.ShouldProfile ? (ProfileStart($"AzureEventHub{options.Support}_{eventHolder.Data.TraceId}")) : default(Guid?); // Check we have en event hub client mEventHubClient = mEventHubClient ?? CreateEventHubClient(); var result = ResourceRequestResult.Unknown; try { //Serialize the blob. var blob = options.SerializerBinary(eventHolder, OriginatorId).Blob; //Encrypt the blob is that is the policy. if (options.EncryptionPolicy != AzureStorageEncryption.None && mEncryption != null) { blob = ServiceHandlers.Encryption[mEncryption].Encrypt(blob); } mEventHubClient.SendAsync(new EventData(blob)).Wait(); result = ResourceRequestResult.Success; } catch (Exception) { result = ResourceRequestResult.Exception; StatisticsInternal.ErrorIncrement(options.Support); throw; } finally { StatisticsInternal.ActiveDecrement(options.Support, start); if (traceId.HasValue) { ProfileEnd(traceId.Value, start, result); } } }
/// <summary> /// This method invokes the event to simulate transmission of the payload. /// </summary> /// <param name="payload">The payload to transmit.</param> /// <param name="retry">The retry count.</param> /// <returns></returns> public override async Task Transmit(TransmissionPayload payload, int retry = 0) { bool tryAgain = false; bool fail = true; try { LastTickCount = Environment.TickCount; if (retry > MaxRetries) { throw new RetryExceededTransmissionException(); } IncomingAction?.Invoke(payload); if (BoundaryLoggingActive) { Collector?.BoundaryLog(ChannelDirection.Outgoing, payload, ChannelId, Priority); } fail = false; } catch (Exception ex) { LogException("Unhandled Exception (Transmit)", ex); if (BoundaryLoggingActive) { Collector?.BoundaryLog(ChannelDirection.Outgoing, payload, ChannelId, Priority, ex); } throw; } finally { if (fail) { StatisticsInternal.ExceptionHitIncrement(); } } if (tryAgain) { await Transmit(payload, ++retry); } }
/// <summary> /// This method creates the necessary task. /// </summary> /// <param name="tracker">The tracker to create a task.</param> /// <returns>Returns a task for the job.</returns> private Task ExecuteTaskCreate(TaskTracker tracker) { //Internal tasks should not block other incoming tasks and they are pass-through requests from another task. tracker.ExecuteTickCount = StatisticsInternal.ActiveIncrement(); var payload = tracker.Context as TransmissionPayload; if (payload != null) { payload.Cancel = tracker.Cts.Token; tracker.ExecuteTask = Dispatcher(payload); } else { tracker.ExecuteTask = tracker.Execute(tracker.Cts.Token); } return(tracker.ExecuteTask); }
/// <summary> /// This method cancels the specific tracker. /// </summary> /// <param name="tracker">The tracker to cancel.</param> private void TaskCancel(TaskTracker tracker) { if (tracker.IsCancelled) { return; } try { StatisticsInternal.TimeoutRegister(1); tracker.Cancel(); LoopSet(); } catch (Exception ex) { Collector?.LogException("TaskCancel exception", ex); } TaskTrackerEvent(DiagnosticOnExecuteTaskCancelled, tracker); }
/// <summary> /// This method marshals the RepositoryHolder and transmits it to the remote Microservice. /// </summary> /// <typeparam Name="KT">The key type.</typeparam> /// <typeparam Name="ET">The entity type.</typeparam> /// <param Name="actionType">The action type.</param> /// <param Name="rq">The repository holder request.</param> /// <returns>Returns an async task that will be signalled when the request completes or times out.</returns> protected override async Task <RepositoryHolder <KT, ET> > TransmitInternal <KT, ET>(string actionType, RepositoryHolder <KT, ET> rq, ProcessOptions?routing = null) { try { StatisticsInternal.ActiveIncrement(); var payload = TransmissionPayload.Create(); // Set the originator key to the correlation id if passed through the rq settings if (rq.Settings != null && !string.IsNullOrEmpty(rq.Settings.CorrelationId)) { payload.Message.OriginatorKey = rq.Settings.CorrelationId; } bool processAsync = rq.Settings == null ? false : rq.Settings.ProcessAsync; payload.Message.ChannelPriority = processAsync ? 0 : 1; payload.Options = routing ?? RoutingDefault ?? ProcessOptions.RouteExternal; payload.Message.Blob = PayloadSerializer.PayloadSerialize(rq); payload.Message.ResponseChannelId = ResponseChannelId; payload.Message.ResponseChannelPriority = payload.Message.ChannelPriority; payload.Message.ChannelId = ChannelId; payload.Message.MessageType = EntityType; payload.Message.ActionType = actionType; payload.MaxProcessingTime = rq.Settings?.WaitTime ?? mDefaultRequestTimespan; return(await TransmitAsync(payload, ProcessResponse <KT, ET>, processAsync)); } catch (Exception ex) { string key = rq != null && rq.Key != null?rq.Key.ToString() : string.Empty; Logger.LogException(string.Format("Error transmitting {0}-{1} internally", actionType, key), ex); throw; } }
/// <summary> /// This method executes the message handler and logs the time statistics. /// </summary> /// <param name="rq">The incoming requests.</param> /// <param name="rs">The outgoing responses.</param> public async virtual Task Execute(TransmissionPayload rq, List <TransmissionPayload> rs) { int timerStart = StatisticsInternal.ActiveIncrement(); mLastAccessed = Environment.TickCount; try { await Action(rq, rs); } catch (Exception ex) { StatisticsInternal.ErrorIncrement(); StatisticsInternal.Ex = ex; throw; } finally { StatisticsInternal.ActiveDecrement(timerStart); } }
/// <summary> /// This method logs the event to DocumentDb /// </summary> /// <param name="logEvent">The event to store in the log.</param> public async Task Log(LogEvent logEvent) { int start = StatisticsInternal.ActiveIncrement(); try { if (logEvent == null) { return; } if (mLoggingPermitted != null && !mLoggingPermitted.Contains(logEvent.Level)) { return; } JObject jObj = JObject.FromObject(logEvent); jObj["id"] = mInstance + Guid.NewGuid().ToString("N"); if (mOriginatorId != null) { jObj["$microservice.instance"] = mOriginatorId.ExternalServiceId; } jObj["$microservice.timestamp"] = DateTime.UtcNow; jObj["$microservice.logtype"] = logEvent.GetType().Name; await mDocDb.Collection.Create(jObj.ToString()); } catch (Exception ex) { StatisticsInternal.ErrorIncrement(); } finally { StatisticsInternal.ActiveDecrement(start); } }
/// <summary> /// This method executes the message handler and logs the time statistics. /// </summary> /// <param name="rq">The incoming requests.</param> /// <param name="rs">The outgoing responses.</param> public async virtual Task Execute(TransmissionPayload rq, List <TransmissionPayload> rs) { int timerStart = StatisticsInternal.ActiveIncrement(); mLastAccessed = timerStart; bool error = false; Exception actionEx = null; try { try { await Action(rq, rs); } catch (Exception ex) { StatisticsInternal.ErrorIncrement(); StatisticsInternal.Ex = ex; error = true; actionEx = ex; if (ExceptionAction == null) { throw; } } if (error) { await ExceptionAction(actionEx, rq, rs); } } finally { StatisticsInternal.ActiveDecrement(timerStart); } }
/// <summary> /// This method is called after a task has completed. /// </summary> /// <param name="tracker">The tracker.</param> /// <param name="failed">A boolean value indicating whether the task has failed.</param> /// <param name="tex">Any exception that was caught as the task executed.</param> private void ExecuteTaskComplete(TaskTracker tracker, bool failed, Exception tex) { tracker.IsFailure = failed; tracker.FailureException = tex; tracker.ToTransmissionPayload()?.TraceWrite("ExecuteTaskComplete", "TaskManager"); try { TaskTracker outTracker; if (mTaskRequests.TryRemove(tracker.Id, out outTracker)) { mAvailability.Decrement(outTracker); try { outTracker.ExecuteComplete?.Invoke(outTracker, failed, tex); } catch (Exception ex) { //We shouldn't throw an exception here, but let's check just in case. Collector?.LogException("ExecuteTaskComplete/ExecuteComplete", ex); } if (outTracker.ExecuteTickCount.HasValue) { StatisticsInternal.ActiveDecrement(outTracker.ExecuteTickCount.Value); } } else { tracker.IsFailure = true; TaskTrackerEvent(DiagnosticOnExecuteTaskCompleteOrphan, tracker); } } catch (Exception ex) { Collector?.LogException($"Task {tracker.Id} has faulted when completing: {ex.Message}", ex); } try { //Signal the poll loop to proceed in case it is waiting, this will check for any pending tasks that require processing. LoopSet(); if (failed) { TaskTrackerEvent(DiagnosticOnExecuteTaskCompleteFailure, tracker); StatisticsInternal.ErrorIncrement(); if (tex != null && tex is AggregateException) { foreach (Exception ex in ((AggregateException)tex).InnerExceptions) { Collector?.LogException(string.Format("Task exception {0}-{1}", tracker.Id, tracker.Caller), ex); } } } else { TaskTrackerEvent(DiagnosticOnExecuteTaskCompleteSuccess, tracker); } } catch { } }