/// <summary> /// Deletes a single message from a queue. /// </summary> /// <typeparam name="T">The type of the payload associated with the message.</typeparam> /// <param name="message">The message to be deleted from a queue.</param> /// <returns>A flag indicating whether or not the specified message has actually been deleted.</returns> public bool Delete <T>(T message) { Guard.ArgumentNotNull(message, "message"); int deletedMsgCount = 0; InflightMessageInfo inflightMessage = null; if (this.inflightMessages.TryRemove(message, out inflightMessage)) { try { var queue = this.queueStorage.GetQueueReference(inflightMessage.QueueName); foreach (var queueMsg in inflightMessage.QueueMessages) { if (Delete(queue, queueMsg)) { deletedMsgCount++; } } // Remove large message blob (if associated with the message being deleted). if (inflightMessage.LargeMessageMetadata != null) { this.overflowStorage.Delete(inflightMessage.LargeMessageMetadata.ContainerName, inflightMessage.LargeMessageMetadata.BlobReference); } } catch { // In the event of a failure, return the removed in-flight message back to the collection. if (!this.inflightMessages.TryAdd(message, inflightMessage)) { this.inflightMessages.AddOrUpdate(message, inflightMessage, (key, oldValue) => { return(inflightMessage); }); } throw; } } return(deletedMsgCount > 0); }
/// <summary> /// Gets a collection of messages from the specified queue and applies the specified visibility timeout. /// </summary> /// <typeparam name="T">The type of the payload associated with the message.</typeparam> /// <param name="queueName">The name of the source queue.</param> /// <param name="count">The number of messages to retrieve.</param> /// <param name="visibilityTimeout">The timeout during which retrieved messages will remain invisible on the queue.</param> /// <returns>The list of messages retrieved from the specified queue.</returns> public IEnumerable <T> Get <T>(string queueName, int count, TimeSpan visibilityTimeout) { Guard.ArgumentNotNullOrEmptyString(queueName, "queueName"); Guard.ArgumentNotZeroOrNegativeValue(count, "count"); try { var queue = this.queueStorage.GetQueueReference(CloudUtility.GetSafeContainerName(queueName)); IEnumerable <CloudQueueMessage> queueMessages = this.retryPolicy.ExecuteAction <IEnumerable <CloudQueueMessage> >(() => { return(queue.GetMessages(Math.Min(count, CloudQueueMessage.MaxNumberOfMessagesToPeek), visibilityTimeout)); }); if (queueMessages != null) { Type queueMsgType = typeof(T); var messages = new List <T>(count); foreach (var queueMsg in queueMessages) { object msgObject = DeserializeQueueMessage(queueMsg, queueMsgType); // Construct an in-flight message object describing the queued message. InflightMessageInfo inflightMessage = new InflightMessageInfo() { QueueName = queue.Name }; // Register the queued message so that it can be located later on. inflightMessage.QueueMessages.Add(queueMsg); if (msgObject is LargeQueueMessageInfo) { // Looks like we are dealing a large message that needs to be fetched from blob storage. inflightMessage.LargeMessageMetadata = msgObject as LargeQueueMessageInfo; // Attempt to retrieve the actual message data from the blob storage. T msgData = this.overflowStorage.Get <T>(inflightMessage.LargeMessageMetadata.ContainerName, inflightMessage.LargeMessageMetadata.BlobReference); // If blob was found, add it to the list of messages being fetched and returned. if (msgData != null) { messages.Add(msgData); msgObject = msgData; } else { // We should skip the current message as it's data has not been located. continue; } } else { messages.Add((T)msgObject); } // Update the in-flight collection, add a new item if necessary, otherwise perform a thread-safe update. this.inflightMessages.AddOrUpdate(msgObject, inflightMessage, (key, oldValue) => { oldValue.QueueMessages.Clear(); return(inflightMessage); }); } return(messages); } } catch (Exception ex) { // We intend to never fail when fetching messages from a queue. We will still need to report on a exception and return an empty list. TraceManager.CloudStorageComponent.TraceError(ex); } // By default, return an empty collection of messages if the above code path didn't return a result. return(new T[0]); }