/// <summary>
        /// Invoke callback.
        /// </summary>
        /// <param name="asyncResults">a collection of IAsyncResult</param>
        private void InvokeCallback(ICollection <IAsyncResult> asyncResults)
        {
            try
            {
                asyncResults.AsParallel <IAsyncResult>().ForAll <IAsyncResult>(
                    (asyncResult) =>
                {
                    try
                    {
                        var reliableState = asyncResult.AsyncState as ReliableState;

                        if (!reliableState.CallbackInvoked())
                        {
                            TraceUtils.TraceWarning(
                                "ReliableQueueClient",
                                "InvokeCallback",
                                "Timeout happens, expected trigger time of message {0} is {1}, client {2}",
                                reliableState.MessageId,
                                reliableState.TriggerTime.ToLocalTime(),
                                this.clientId);

                            reliableState.Timeout = true;

                            reliableState.Callback(asyncResult);
                        }
                        else
                        {
                            TraceUtils.TraceVerbose(
                                "ReliableQueueClient",
                                "InvokeCallback",
                                "Callback of message {0} is already invoked, client {1}",
                                reliableState.MessageId,
                                this.clientId);
                        }
                    }
                    catch (Exception e)
                    {
                        TraceUtils.TraceError(
                            "ReliableQueueClient",
                            "InvokeCallback",
                            "Invoking callback failed, {0}, client {1}",
                            e,
                            this.clientId);
                    }
                });
            }
            catch (Exception e)
            {
                TraceUtils.TraceError(
                    "ReliableQueueClient",
                    "InvokeCallback",
                    "Error occurs, {0}, client {1}",
                    e,
                    this.clientId);
            }
        }
Beispiel #2
0
        /// <summary>
        /// Async method for delete message.
        /// </summary>
        /// <param name="asyncResult">async result</param>
        private void EndDeleteMessage(IAsyncResult asyncResult)
        {
            UniqueId messageId = null;

            try
            {
                Tuple <object, UniqueId> tuple = asyncResult.AsyncState as Tuple <object, UniqueId>;

                messageId = tuple.Item2;

                // Notice: (azure burst) for perf consideration, on-premise
                // broker does not need to delete blob (for large message),
                // they will be removed when broker terminates. And broker
                // service also conducts cleanup.
                if (this.onAzure)
                {
                    if (messageId != null)
                    {
                        TraceUtils.TraceVerbose(
                            "AzureStorageClient",
                            "EndDeleteMessage",
                            "Delete message {0} from storage blob.",
                            messageId);

                        try
                        {
                            this.DeleteBlob(messageId);
                        }
                        catch (Exception e)
                        {
                            TraceUtils.TraceError("AzureStorageClient", "EndDeleteMessage", "DeleteBlob failed, {0}", e);
                        }
                    }
                }

                this.Queue.EndDeleteMessage(asyncResult);
            }
            catch (Exception e)
            {
                string messageIdString = string.Empty;

                if (messageId != null)
                {
                    messageIdString = messageId.ToString();
                }

                TraceUtils.TraceError(
                    "AzureStorageClient",
                    "EndDeleteMessage",
                    "Error occurs when delete message {0}, {1}",
                    messageIdString,
                    e);
            }
        }
        /// <summary>
        /// Async method for add message.
        /// </summary>
        /// <param name="asyncResult">async result</param>
        public void EndAddMessage(IAsyncResult asyncResult)
        {
            var reliableState = asyncResult.AsyncState as ReliableState;

            if (reliableState.Timeout)
            {
                throw new TimeoutException(
                          string.Format(
                              "Callback is lost after {0} minutes, client {1}",
                              CallbackTimeout.TotalMinutes,
                              this.clientId));
            }

            if (!reliableState.CallbackInvoked())
            {
                TraceUtils.TraceVerbose(
                    "ReliableQueueClient",
                    "EndAddMessage",
                    "Message {0}, client {1}",
                    reliableState.MessageId,
                    this.clientId);

                try
                {
                    this.cloudQueue.EndAddMessage(asyncResult);
                }
                catch (Exception e)
                {
                    TraceUtils.TraceError(
                        "ReliableQueueClient",
                        "EndAddMessage",
                        "EndAddMessage failed with excpetion {0}, client {1}",
                        e,
                        this.clientId);
                }
                finally
                {
                    TraceUtils.TraceVerbose(
                        "ReliableQueueClient",
                        "EndAddMessage",
                        "Try remove the message {0} from cache, client {1}",
                        reliableState.MessageId,
                        this.clientId);

                    IAsyncResult tmp;

                    this.asyncResultCache.TryRemove(reliableState.MessageId, out tmp);
                }
            }
        }
Beispiel #4
0
        /// <summary>
        /// Async method for add message. If the message size hits limit, store
        /// it in blob and add a referral message in queue.
        /// </summary>
        /// <param name="messageData">raw data of message</param>
        /// <param name="messageId">wcf message Id</param>
        /// <param name="callback">callback method</param>
        /// <param name="state">state object</param>
        /// <returns>async state</returns>
        public IAsyncResult BeginAddMessage(byte[] messageData, UniqueId messageId, AsyncCallback callback, ReliableQueueClient.ReliableState state)
        {
            CloudQueueMessage message = new CloudQueueMessage(messageData);

            try
            {
                if (messageData.Length <= MessageSizeBoundary)
                {
                    message = new CloudQueueMessage(messageData);

                    return(this.ReliableQueue.BeginAddMessage(message, callback, state));
                }
            }
            catch (ArgumentException e)
            {
                // according to the test, when payload is <= 48KB, it can fit
                // in a queue message. otherwise, ArgumentException occurs. but
                // there is no doc about this. so catch ArgumentException here,
                // and store message to blob below.
                TraceUtils.TraceWarning("AzureStorageClient", "BeginAddMessage", "BeginAddMessage failed, {0}", e);
            }
            catch (Exception ex)
            {
                TraceUtils.TraceWarning("AzureStorageClient", "BeginAddMessage", "BeginAddMessage failed, {0}", ex);
                throw;
            }

            TraceUtils.TraceVerbose("AzureStorageClient", "BeginAddMessage", "Upload message {0} to storage blob.", messageId);

            this.UploadBlob(messageData, messageId);

            // Store a referral message in Azure queue with the same message Id
            // as the original message. It redirects proxy to get real message
            // from the blob.
            Message referralMessage = Message.CreateMessage(MessageVersion.Default, string.Empty);

            referralMessage.Headers.MessageId = messageId;

            referralMessage.Headers.Add(
                MessageHeader.CreateHeader(Constant.MessageHeaderBlob, Constant.HpcHeaderNS, string.Empty));

            message = new CloudQueueMessage(AzureQueueItem.Serialize(referralMessage));

            return(this.ReliableQueue.BeginAddMessage(message, callback, state));
        }
        /// <summary>
        /// Async method for add message to queue.
        /// </summary>
        /// <param name="message">queue message</param>
        /// <param name="callback">callback method</param>
        /// <param name="state">state object</param>
        /// <returns>async result</returns>
        public IAsyncResult BeginAddMessage(CloudQueueMessage message, AsyncCallback callback, ReliableState state)
        {
            state.Callback = callback;

            state.TriggerTime = DateTime.UtcNow + CallbackTimeout;

            IAsyncResult result = this.cloudQueue.BeginAddMessage(message, callback, state);

            this.asyncResultCache.AddOrUpdate(state.MessageId, result, (key, value) => result);

            TraceUtils.TraceVerbose(
                "ReliableQueueClient",
                "BeginAddMessage",
                "Add message {0} to the local cache, client {1}",
                state.MessageId,
                this.clientId);

            return(result);
        }
Beispiel #6
0
        /// <summary>
        /// Dispose current object.
        /// </summary>
        /// <param name="disposing">disposing flag</param>
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);

            if (disposing)
            {
                if (this.ReliableQueue != null)
                {
                    try
                    {
                        this.ReliableQueue.Close();
                    }
                    catch (Exception e)
                    {
                        TraceUtils.TraceVerbose("AzureStorageClient", "Dispose", "Closing ReliableQueue failed, {0}", e);
                    }

                    this.ReliableQueue = null;
                }
            }
        }
Beispiel #7
0
            /// <summary>
            /// Callback of the BeginGetMessages method.
            /// </summary>
            /// <param name="ar">async result</param>
            private void GetMessagesCallback(IAsyncResult ar)
            {
                Guid callId = (Guid)ar.AsyncState;

                try
                {
                    IEnumerable <CloudQueueMessage> messages = null;

                    try
                    {
                        TraceUtils.TraceVerbose(
                            "MessageRetriever.Worker",
                            "GetMessagesCallback",
                            "Call EndGetMessages, worker {0}, call Id {1}, queue {2}",
                            this.workerId,
                            callId,
                            this.queue.Name);

                        messages = this.queue.EndGetMessages(ar);

                        TraceUtils.TraceVerbose(
                            "MessageRetriever.Worker",
                            "GetMessagesCallback",
                            "EndGetMessages returns, worker {0}, call Id {1}, queue {2}",
                            this.workerId,
                            callId,
                            this.queue.Name);
                    }
                    catch (StorageException e)
                    {
                        TraceUtils.TraceError(
                            "MessageRetriever.Worker",
                            "GetMessagesCallback",
                            "EndGetMessages failed, worker {0}, call Id {1}, queue {2}, error code {3}, {4}",
                            this.workerId,
                            callId,
                            this.queue.Name,
                            BurstUtility.GetStorageErrorCode(e),
                            e);

                        this.HandleInvalidQueue(e);
                    }
                    catch (Exception e)
                    {
                        TraceUtils.TraceError(
                            "MessageRetriever.Worker",
                            "GetMessagesCallback",
                            "EndGetMessages failed, worker {0}, call Id {1}, queue {2}, {3}",
                            this.workerId,
                            callId,
                            this.queue.Name,
                            e);
                    }
                    finally
                    {
                        this.waitHandler.Set();
                    }

                    int count = 0;

                    if (messages != null)
                    {
                        count = messages.Count <CloudQueueMessage>();
                    }

                    if (count > 0)
                    {
                        TraceUtils.TraceVerbose(
                            "MessageRetriever.Worker",
                            "GetMessagesCallback",
                            "Get {0} messages from the queue, worker {1}, call Id {2}, queue {3}",
                            count,
                            this.workerId,
                            callId,
                            this.queue.Name);

                        this.sleepPeriod = 0;

                        // Make sure messageHandler is a fast operation, call
                        // it before getting messages next time, in case
                        // current thread doesn't get chance on time to call
                        // messageHandler if BeginGetMessages's callback is
                        // invoked on current thread again.
                        if (this.messageHandler != null)
                        {
                            try
                            {
                                this.messageHandler(messages);
                            }
                            catch (Exception e)
                            {
                                TraceUtils.TraceError(
                                    "MessageRetriever.Worker",
                                    "GetMessagesCallback",
                                    "Message handler throws exception, worker {0}, call Id {1}, queue {2}, {3}",
                                    this.workerId,
                                    callId,
                                    this.queue.Name,
                                    e);
                            }
                        }

                        this.InternalBeginGetMessages(null);
                    }
                    else
                    {
                        TraceUtils.TraceVerbose(
                            "MessageRetriever.Worker",
                            "GetMessagesCallback",
                            "Get 0 message from the queue, worker {0}, call Id {1}, queue {2}",
                            this.workerId,
                            callId,
                            this.queue.Name);

                        this.TriggerTimer();
                    }
                }
                catch (Exception e)
                {
                    TraceUtils.TraceError(
                        "MessageRetriever.Worker",
                        "GetMessagesCallback",
                        "Error occurs, worker {0}, call Id {1}, queue {2}, {3}",
                        this.workerId,
                        callId,
                        this.queue.Name,
                        e);

                    this.TriggerTimer();
                }
            }
Beispiel #8
0
            /// <summary>
            /// Call cloud queue's async method to get messages.
            /// </summary>
            /// <param name="state">state object</param>
            private void InternalBeginGetMessages(object state)
            {
                if (this.stop)
                {
                    // if current worker already stops, just return
                    return;
                }

                // this Id is only used in trace log to track latency for each
                // BeginGetMessages method call
                Guid callId = Guid.NewGuid();

                try
                {
                    TraceUtils.TraceVerbose(
                        "MessageRetriever.Worker",
                        "InternalGetMessages",
                        "Call BeginGetMessages, worker {0}, call Id {1}, queue {2}",
                        this.workerId,
                        callId,
                        this.queue.Name);

                    this.waitHandler.Reset();

                    this.queue.BeginGetMessages(Constant.GetQueueMessageBatchSize, this.visibleTimeout, null, null, this.GetMessagesCallback, callId);

                    TraceUtils.TraceVerbose(
                        "MessageRetriever.Worker",
                        "InternalGetMessages",
                        "BeginGetMessages returns, worker {0}, call Id {1}, queue {2}",
                        this.workerId,
                        callId,
                        this.queue.Name);
                }
                catch (StorageException e)
                {
                    this.waitHandler.Set();

                    TraceUtils.TraceError(
                        "MessageRetriever.Worker",
                        "InternalGetMessages",
                        "BeginGetMessages failed, worker {0}, call Id {1}, queue {2}, error code {3}, {4}",
                        this.workerId,
                        callId,
                        this.queue.Name,
                        BurstUtility.GetStorageErrorCode(e),
                        e);

                    this.HandleInvalidQueue(e);

                    this.TriggerTimer();
                }
                catch (Exception e)
                {
                    this.waitHandler.Set();

                    TraceUtils.TraceError(
                        "MessageRetriever.Worker",
                        "InternalGetMessages",
                        "Error occurs, worker {0}, call Id {1}, queue {2}, {3}",
                        this.workerId,
                        callId,
                        this.queue.Name,
                        e);

                    this.TriggerTimer();
                }
            }
        /// <summary>
        /// Callback method of the timer.
        /// </summary>
        /// <param name="state">state object</param>
        private void TimerCallback(object state)
        {
            TraceUtils.TraceVerbose(
                "ReliableQueueClient",
                "TimerCallback",
                "Enter timer callback, client {0}",
                this.clientId);

            List <IAsyncResult> lostCallbacks = new List <IAsyncResult>();

            List <UniqueId> messageIds = new List <UniqueId>();

            try
            {
                IAsyncResult result;

                DateTime utcNow = DateTime.UtcNow;

                var keys = this.asyncResultCache.Keys;

                TraceUtils.TraceVerbose(
                    "ReliableQueueClient",
                    "TimerCallback",
                    "There are {0} messages in the local cache, client {1}",
                    keys.Count,
                    this.clientId);

                foreach (UniqueId messageId in keys)
                {
                    if (this.asyncResultCache.TryGetValue(messageId, out result))
                    {
                        var reliableState = result.AsyncState as ReliableState;

                        if (reliableState.TriggerTime <= utcNow)
                        {
                            lostCallbacks.Add(result);

                            messageIds.Add(messageId);

                            TraceUtils.TraceVerbose(
                                "ReliableQueueClient",
                                "TimerCallback",
                                "Expected trigger time of message {0} is {1}, get it, client {2}",
                                messageId,
                                reliableState.TriggerTime.ToLocalTime(),
                                this.clientId);
                        }
                        else
                        {
                            TraceUtils.TraceVerbose(
                                "ReliableQueueClient",
                                "TimerCallback",
                                "Expected trigger time of message {0} is {1}, ignore it, client {2}",
                                messageId,
                                reliableState.TriggerTime.ToLocalTime(),
                                this.clientId);
                        }
                    }
                }

                // invoke the lost callbacks before deleting them from cache
                if (lostCallbacks.Count > 0)
                {
                    TraceUtils.TraceVerbose(
                        "ReliableQueueClient",
                        "TimerCallback",
                        "Invoke callbacks, count {0}, client {1}",
                        lostCallbacks.Count,
                        this.clientId);

                    this.InvokeCallback(lostCallbacks);
                }

                // delete callbacks from cache
                if (messageIds.Count > 0)
                {
                    foreach (UniqueId messageId in messageIds)
                    {
                        IAsyncResult tmp;

                        this.asyncResultCache.TryRemove(messageId, out tmp);

                        TraceUtils.TraceVerbose(
                            "ReliableQueueClient",
                            "TimerCallback",
                            "Remove message {0} from cache, client {1}",
                            messageId,
                            this.clientId);
                    }
                }
            }
            catch (Exception e)
            {
                TraceUtils.TraceError(
                    "ReliableQueueClient",
                    "TimerCallback",
                    "Error occurs, {0}, client {1}",
                    e,
                    this.clientId);
            }
        }