/// <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 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; } }
private void ActionSync(TransmissionPayload incoming, List <TransmissionPayload> outgoing) { var blahIn = PayloadSerializer.PayloadDeserialize <Blah>(incoming); var rs = incoming.ToResponse(); rs.Message.Blob = PayloadSerializer.PayloadSerialize(blahIn.Message); rs.Message.Status = "204"; rs.Message.StatusDescription = "Hello"; outgoing.Add(rs); }
private async Task ActionAsync(TransmissionPayload incoming, List <TransmissionPayload> outgoing) { var blahIn = PayloadSerializer.PayloadDeserialize <Blah>(incoming); var rs = incoming.ToResponse(); rs.Message.Blob.SetObject("Freaky"); rs.Message.Status = "204"; rs.Message.StatusDescription = "Hello"; outgoing.Add(rs); //return Task.FromResult(0); }
/// <summary> /// This method is called when an entity of the cache type is updated or deleted. /// </summary> /// <param name="rq">The request.</param> /// <param name="rs">The response.</param> /// <returns></returns> protected virtual async Task EntityChangeNotification(TransmissionPayload rq, List <TransmissionPayload> rs) { try { EntityChangeReference <K> entityChangeReference = PayloadSerializer.PayloadDeserialize <EntityChangeReference <K> >(rq); var key = entityChangeReference.Key; Remove(key); } catch (Exception ex) { Collector?.LogException("Unable to retrieve the entity change reference", ex); } }
/// <summary> /// /// </summary> /// <typeparam name="CM"></typeparam> /// <typeparam name="PM"></typeparam> /// <param name="action"></param> /// <param name="exceptionAction"></param> protected void CommandRegister <CM, PM>( Func <PM, TransmissionPayload, List <TransmissionPayload>, Task> action, Func <Exception, TransmissionPayload, List <TransmissionPayload>, Task> exceptionAction = null) where CM : IMessageContract { Func <TransmissionPayload, List <TransmissionPayload>, Task> actionReduced = async(m, l) => { PM payload = PayloadSerializer.PayloadDeserialize <PM>(m); await action(payload, m, l); }; CommandRegister <CM>(actionReduced, exceptionAction); }
private async Task ActionAsync(TransmissionPayload incoming, List <TransmissionPayload> outgoing) { var blahIn = PayloadSerializer.PayloadDeserialize <Blah>(incoming); var rs = incoming.ToResponse(); rs.Message.Blob = PayloadSerializer.PayloadSerialize(new Blah { ContentId = blahIn.ContentId, Message = "Howdy" }); rs.MessageObject = "Freaky"; rs.Message.Status = "204"; rs.Message.StatusDescription = "Hello"; outgoing.Add(rs); }
/// <summary> /// This method registers the specific persistence handler. /// </summary> /// <typeparam Name="KT">The key type.</typeparam> /// <typeparam Name="ET">The entity type.</typeparam> /// <param name="actionType">The action type identifier</param> /// <param name="action">The action to process the command.</param> /// <param name="logEventOnSuccess"></param> /// <param name="preaction"></param> /// <param name="postaction"></param> /// <param name="timeoutcorrect"></param> /// <param name="retryOnTimeout"></param> /// <param name="channelId"></param> /// <param name="entityType"></param> protected virtual void PersistenceCommandRegister <KT, ET>(string actionType , Func <PersistenceRequestHolder <KT, ET>, Task> action , bool logEventOnSuccess = false , Func <PersistenceRequestHolder <KT, ET>, Task <bool> > preaction = null , Func <PersistenceRequestHolder <KT, ET>, Task> postaction = null , Func <PersistenceRequestHolder <KT, ET>, Task <bool> > timeoutcorrect = null , int?retryOnTimeout = null , string channelId = null , string entityType = null ) { Func <TransmissionPayload, List <TransmissionPayload>, Task> actionPayload = async(incoming, outgoing) => { var profileHolder = ProfileStart <KT, ET>(incoming, outgoing); try { var rsMessage = incoming.Message.ToResponse(); rsMessage.ChannelId = incoming.Message.ResponseChannelId; rsMessage.ChannelPriority = incoming.Message.ResponseChannelPriority; rsMessage.MessageType = incoming.Message.MessageType; rsMessage.ActionType = ""; var rsPayload = new TransmissionPayload(rsMessage); bool hasTimedOut = false; try { RepositoryHolder <KT, ET> rqTemp = incoming.MessageObject as RepositoryHolder <KT, ET>; //Deserialize the incoming payloadRq request if (rqTemp == null) { rqTemp = PayloadSerializer.PayloadDeserialize <RepositoryHolder <KT, ET> >(incoming); } profileHolder.Rq = new PersistenceRepositoryHolder <KT, ET>(rqTemp); if (profileHolder.Rq.Timeout == null) { profileHolder.Rq.Timeout = TimeSpan.FromSeconds(10); } bool preactionFailed = false; try { bool retryExceeded = false; do { int attempt = Environment.TickCount; //Create the payloadRs holder, and discard any previous version. profileHolder.Rs = new PersistenceRepositoryHolder <KT, ET>(); if (preaction != null && !(await preaction(profileHolder))) { preactionFailed = true; break; } //Call the specific command to process the action, i.e Create, Read, Update, Delete ... etc. await action(profileHolder); //Flag if the request times out at any point. //This may be required later when checking whether the action was actually successful. hasTimedOut |= profileHolder.Rs.IsTimeout; //OK, if this is not a time out then it is successful if (!profileHolder.Rs.IsTimeout && !profileHolder.Rs.ShouldRetry) { break; } ProfileRetry(profileHolder, attempt); if (profileHolder.Rs.IsTimeout) { Logger.LogMessage(LoggingLevel.Warning, $"Timeout occured for {EntityType} {actionType} for request:{profileHolder.Rq} with response:{profileHolder.Rs}", "DBTimeout"); } profileHolder.Rq.IsRetry = true; //These should not be counted against the limit. if (!profileHolder.Rs.ShouldRetry) { profileHolder.Rq.Retry++; } profileHolder.Rq.IsTimeout = false; retryExceeded = incoming.Cancel.IsCancellationRequested || profileHolder.Rq.Retry > mPolicy.PersistenceRetryPolicy.GetMaximumRetries(incoming); }while (!retryExceeded); //Signal to the underlying comms channel that the message has been processed successfully. incoming.Signal(!retryExceeded); // If we have exceeded the retry limit then Log error if (retryExceeded) { Log(actionType , profileHolder , LoggingLevel.Error , $"Retry limit has been exceeded (cancelled ({incoming.Cancel.IsCancellationRequested})) for {EntityType} {actionType} for {profileHolder.Rq} after {incoming.Message?.FabricDeliveryCount} delivery attempts" , "DBRetry"); profileHolder.result = ResourceRequestResult.RetryExceeded; } } catch (Exception ex) { LogException(actionType, profileHolder, ex); incoming.SignalFail(); profileHolder.result = ResourceRequestResult.Exception; } bool logEventSource = !preactionFailed && logEventOnSuccess && profileHolder.Rs.IsSuccess; if (!profileHolder.Rs.IsSuccess && hasTimedOut && timeoutcorrect != null && profileHolder.result != ResourceRequestResult.Exception) { if (await timeoutcorrect(profileHolder)) { logEventSource = true; Logger.LogMessage(LoggingLevel.Info , string.Format("Recovered timeout sucessfully for {0}-{1} for request:{2} - response:{3}", EntityType, actionType, profileHolder.Rq, profileHolder.Rs) , "DBTimeout"); } else { Logger.LogMessage(LoggingLevel.Error , string.Format("Not recovered timeout for {0}-{1} for request:{2} - response:{3}", EntityType, actionType, profileHolder.Rq, profileHolder.Rs) , "DBTimeout"); } } if (logEventSource && profileHolder.Rs.ShouldLogEventSource) { await LogEventSource(actionType, profileHolder); } if (!preactionFailed && postaction != null) { await postaction(profileHolder); } //Serialize the payloadRs var reposHolder = profileHolder.Rs.ToRepositoryHolder(); rsPayload.MessageObject = reposHolder; rsPayload.Message.Blob = PayloadSerializer.PayloadSerialize(reposHolder); rsPayload.Message.Status = "200"; if (!profileHolder.result.HasValue) { profileHolder.result = ResourceRequestResult.Success; } } catch (Exception ex) { incoming.SignalFail(); rsPayload.Message.Status = "500"; rsPayload.Message.StatusDescription = ex.Message; Logger.LogException($"Error processing message (was cancelled({incoming.Cancel.IsCancellationRequested}))-{EntityType}-{actionType}-{profileHolder.Rq}", ex); profileHolder.result = ResourceRequestResult.Exception; } // check whether we need to send a response message. If this is async and AsyncResponse is not set to true, // then by default we do not send a response message to cut down on unnecessary traffic. if (profileHolder.Rq == null || profileHolder.Rq.Settings == null || !profileHolder.Rq.Settings.ProcessAsync) { outgoing.Add(rsPayload); } } finally { ProfileEnd(profileHolder); } }; if (channelId == null) { channelId = ChannelId ?? string.Empty; } if (entityType == null) { entityType = EntityType; } CommandRegister( channelId.ToLowerInvariant() , entityType.ToLowerInvariant() , actionType.ToLowerInvariant() , actionPayload); }