Exemple #1
0
        public void SendAsync <T>(T methodObj, object methodState, Action <IMessageSentResult <T> > methodResultCallBack,
                                  IServiceBusSerializer methodSerializer = null, IDictionary <string, object> methodMetadata = null)
        {
            Guard.ArgumentNotNull(methodObj, "obj");
            Guard.ArgumentNotNull(methodResultCallBack, "resultCallBack");

            methodSerializer = methodSerializer ?? configuration.DefaultSerializer.Create();

            var sw = new Stopwatch();

            sw.Start();

            Action <T, object, Action <IMessageSentResult <T> >, IServiceBusSerializer, IDictionary <string, object> > sendAction = null;

            sendAction = ((obj, state, resultCallBack, serializer, metadata) => {
                IBrokeredMessage message = null;
                Exception failureException = null;
                bool resultSent = false; //I am not able to determine when the exception block is called.

                // Use a retry policy to execute the Send action in an asynchronous and reliable fashion.
                retryPolicy.ExecuteAction
                (
                    (cb) => {
                    failureException = null;     //we may retry so we must null out the error.
                    try {
                        // A new BrokeredMessage instance must be created each time we send it. Reusing the original BrokeredMessage instance may not
                        // work as the state of its BodyStream cannot be guaranteed to be readable from the beginning.
                        message = configurationFactory.MessageFactory.CreateBrokeredMessage(serializer.Serialize(obj));

                        message.MessageId = Guid.NewGuid().ToString();
                        message.Properties.Add(TYPE_HEADER_NAME, obj.GetType().FullName.Replace('.', '_'));

                        if (metadata != null)
                        {
                            foreach (var item in metadata)
                            {
                                message.Properties.Add(item.Key, item.Value);
                            }
                        }

                        logger.Debug("sendAction BeginSend Type={0} Serializer={1} MessageId={2}", obj.GetType().FullName, serializer.GetType().FullName, message.MessageId);

                        // Send the event asynchronously.
                        defaultClient.BeginSend(message, cb, null);
                    }
                    catch (Exception ex) {
                        failureException = ex;
                        throw;
                    }
                },
                    (ar) => {
                    try {
                        failureException = null;     //we may retry so we must null out the error.
                        // Complete the asynchronous operation. This may throw an exception that will be handled internally by the retry policy.
                        logger.Debug("sendAction EndSend Begin Type={0} Serializer={1} MessageId={2}", obj.GetType().FullName, serializer.GetType().FullName, message.MessageId);
                        defaultClient.EndSend(ar);
                        logger.Debug("sendAction EndSend End Type={0} Serializer={1} MessageId={2}", obj.GetType().FullName, serializer.GetType().FullName, message.MessageId);
                    }
                    catch (Exception ex) {
                        failureException = ex;
                        throw;
                    }
                },
                    () => {
                    // Ensure that any resources allocated by a BrokeredMessage instance are released.
                    if (message != null)
                    {
                        message.Dispose();
                        message = null;
                    }
                    if (serializer != null)
                    {
                        serializer.Dispose();
                        serializer = null;
                    }
                    sw.Stop();
                    if (!resultSent)
                    {
                        resultSent = true;
                        ExtensionMethods.ExecuteAndReturn(() => resultCallBack(new MessageSentResult <T>()
                        {
                            IsSuccess = failureException == null,
                            State = state,
                            ThrownException = failureException,
                            TimeSpent = sw.Elapsed
                        }));
                    }
                },
                    (ex) => {
                    // Always dispose the BrokeredMessage instance even if the send operation has completed unsuccessfully.
                    if (message != null)
                    {
                        message.Dispose();
                        message = null;
                    }
                    if (serializer != null)
                    {
                        serializer.Dispose();
                        serializer = null;
                    }
                    failureException = ex;

                    // Always log exceptions.
                    logger.Error <Exception>("Send failed {0}", ex);

                    sw.Stop();

                    //see if the reason is the topic was deleted and if it was, create the topic and set a new error since there will be no receivers.

                    var topicException = ex as MessagingEntityNotFoundException;
                    if (topicException != null && topicException.Detail != null && topicException.Detail.Message.IndexOf("40400") > -1)
                    {
                        logger.Info("Topic was deleted. Attempting to Recreate.");
                        EnsureTopic(this.configuration.TopicName, this.configuration.EnablePartitioning);
                        failureException = new TopicDeletedException();
                        logger.Info("Topic was deleted. Recreate Complete.");
                    }

                    if (!resultSent)
                    {
                        resultSent = true;
                        ExtensionMethods.ExecuteAndReturn(() => resultCallBack(new MessageSentResult <T>()
                        {
                            IsSuccess = failureException == null,
                            State = state,
                            ThrownException = failureException,
                            TimeSpent = sw.Elapsed
                        }));
                    }
                }
                ); //asyc
            });    //action

            sendAction(methodObj, methodState, methodResultCallBack, methodSerializer, methodMetadata);
        }
Exemple #2
0
        private void ProcessMessagesForSubscriptionLegacy()
        {
            try {
                logger.Info("ProcessMessagesForSubscription Message Start {0} Declared {1} MessageTytpe {2}, IsReusable {3}", data.EndPointData.SubscriptionName,
                            data.EndPointData.DeclaredType.ToString(), data.EndPointData.MessageType.ToString(), data.EndPointData.IsReusable);

                var gt         = typeof(IReceivedMessage <>).MakeGenericType(data.EndPointData.MessageType);
                var methodInfo = data.EndPointData.DeclaredType.GetMethod("Handle", new Type[] { gt });

                var waitTimeout = TimeSpan.FromSeconds(30);

                // Declare an action acting as a callback whenever a message arrives on a queue.
                AsyncCallback completeReceive = null;

                // Declare an action acting as a callback whenever a non-transient exception occurs while receiving or processing messages.
                Action <Exception> recoverReceive = null;

                // Declare an action implementing the main processing logic for received messages.
                Action <AzureReceiveState> processMessage = ((receiveState) => {
                    // Put your custom processing logic here. DO NOT swallow any exceptions.
                    ProcessMessageCallBack(receiveState);
                });

                bool messageReceived = false;

                bool lastAttemptWasError = false;

                // Declare an action responsible for the core operations in the message receive loop.
                Action receiveMessage = (() => {
                    // Use a retry policy to execute the Receive action in an asynchronous and reliable fashion.
                    retryPolicy.ExecuteAction
                    (
                        (cb) => {
                        if (lastAttemptWasError)
                        {
                            if (data.EndPointData.AttributeData.PauseTimeIfErrorWasThrown > 0)
                            {
                                Thread.Sleep(data.EndPointData.AttributeData.PauseTimeIfErrorWasThrown);
                            }
                            else
                            {
                                Thread.Sleep(1000);
                            }
                        }
                        // Start receiving a new message asynchronously.
                        data.Client.BeginReceive(waitTimeout, cb, null);
                    },
                        (ar) => {
                        messageReceived = false;
                        // Make sure we are not told to stop receiving while we were waiting for a new message.
                        if (!data.CancelToken.IsCancellationRequested)
                        {
                            IBrokeredMessage msg = null;
                            bool isError = false;
                            try {
                                // Complete the asynchronous operation. This may throw an exception that will be handled internally by retry policy.
                                msg = data.Client.EndReceive(ar);

                                // Check if we actually received any messages.
                                if (msg != null)
                                {
                                    // Make sure we are not told to stop receiving while we were waiting for a new message.
                                    if (!data.CancelToken.IsCancellationRequested)
                                    {
                                        // Process the received message.
                                        messageReceived = true;
                                        logger.Debug("ProcessMessagesForSubscription Start received new message: {0}", data.EndPointData.SubscriptionNameDebug);
                                        var receiveState = new AzureReceiveState(data, methodInfo, serializer, msg);
                                        processMessage(receiveState);
                                        logger.Debug("ProcessMessagesForSubscription End received new message: {0}", data.EndPointData.SubscriptionNameDebug);
                                    }
                                }
                            }
                            catch (Exception) {
                                isError = true;
                                throw;
                            }
                            finally {
                                // With PeekLock mode, we should mark the failed message as abandoned.
                                if (msg != null)
                                {
                                    if (data.Client.Mode == ReceiveMode.PeekLock)
                                    {
                                        if (isError)
                                        {
                                            // Abandons a brokered message. This will cause Service Bus to unlock the message and make it available
                                            // to be received again, either by the same consumer or by another completing consumer.
                                            SafeAbandon(msg);
                                        }
                                        else
                                        {
                                            // Mark brokered message as completed at which point it's removed from the queue.
                                            SafeComplete(msg);
                                        }
                                    }
                                    msg.Dispose();
                                }
                            }
                        }
                        // Invoke a custom callback method to indicate that we have completed an iteration in the message receive loop.
                        completeReceive(ar);
                    },
                        () => {
                        //do nothing, we completed.
                    },
                        (ex) => {
                        // Invoke a custom action to indicate that we have encountered an exception and
                        // need further decision as to whether to continue receiving messages.
                        recoverReceive(ex);
                    });
                });

                // Initialize a custom action acting as a callback whenever a message arrives on a queue.
                completeReceive = ((ar) => {
                    lastAttemptWasError = false;
                    if (!data.CancelToken.IsCancellationRequested)
                    {
                        // Continue receiving and processing new messages until we are told to stop.
                        receiveMessage();
                    }
                    else
                    {
                        data.SetMessageLoopCompleted();
                    }

                    if (messageReceived)
                    {
                        logger.Debug("ProcessMessagesForSubscription Message Complete={0} Declared={1} MessageTytpe={2} IsReusable={3}", data.EndPointData.SubscriptionName,
                                     data.EndPointData.DeclaredType.ToString(), data.EndPointData.MessageType.ToString(), data.EndPointData.IsReusable);
                    }
                });

                // Initialize a custom action acting as a callback whenever a non-transient exception occurs while receiving or processing messages.
                recoverReceive = ((ex) => {
                    // Just log an exception. Do not allow an unhandled exception to terminate the message receive loop abnormally.
                    lastAttemptWasError = true;

                    if (!data.CancelToken.IsCancellationRequested && typeof(ThreadAbortException) != ex.GetType())
                    {
                        //The subscription may have been deleted. If it was, then we want to recreate it.
                        var subException = ex as MessagingEntityNotFoundException;

                        if (subException != null && subException.Detail != null && subException.Detail.Message.IndexOf("40400") > -1)
                        {
                            logger.Info("Subscription was deleted. Attempting to Recreate.");
                            Configure(endpoint);
                            logger.Info("Subscription was deleted. Recreated.");
                        }
                        else
                        {
                            logger.Error(string.Format("ProcessMessagesForSubscription Message Error={0} Declared={1} MessageTytpe={2} IsReusable={3} Error={4}",
                                                       data.EndPointData.SubscriptionName,
                                                       data.EndPointData.DeclaredType.ToString(),
                                                       data.EndPointData.MessageType.ToString(),
                                                       data.EndPointData.IsReusable,
                                                       ex.ToString()));
                        }

                        // Continue receiving and processing new messages until we are told to stop regardless of any exceptions.
                        receiveMessage();
                    }
                    else
                    {
                        data.SetMessageLoopCompleted();
                    }

                    if (messageReceived)
                    {
                        logger.Debug("ProcessMessagesForSubscription Message Complete={0} Declared={1} MessageTytpe={2} IsReusable={3}", data.EndPointData.SubscriptionName,
                                     data.EndPointData.DeclaredType.ToString(), data.EndPointData.MessageType.ToString(), data.EndPointData.IsReusable);
                    }
                });

                // Start receiving messages asynchronously.
                receiveMessage();
            }
            catch (ThreadAbortException) {
                //do nothing, let it exit
            }
            catch (Exception ex) {
                failCounter++;
                logger.Error("ProcessMessagesForSubscription: Error during receive during loop. See details and fix: {0}", ex);
                if (failCounter < 100)
                {
                    //try again
                    ProcessMessagesForSubscription();
                }
            }
        }