/// <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;
            }
        }
예제 #2
0
        /// <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;
            }
        }
예제 #3
0
        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);
        }
예제 #4
0
        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);
        }
예제 #7
0
        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);
        }
예제 #8
0
        /// <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);
        }