/// <summary>
        ///     <para>Deletes an <see cref="IQueueMessage" /></para>
        ///     <para>under a synchronisation token and cancels related jobs (i.e. keep-alive operations).</para>
        /// </summary>
        /// <param name="asyncLock">An object that's responsible for synchronising access to shared resources in an asynchronous manner.</param>
        /// <param name="message">The message to delete.</param>
        /// <param name="messageSpecificCancellationTokenSource">The message-specific cancellation token.</param>
        private async Task SyncDeleteMessage(
            [NotNull] AsyncLock asyncLock,
            [NotNull] QueueMessageWrapper message,
            [CanBeNull] CancellationTokenSource messageSpecificCancellationTokenSource)
        {
            Guard.NotNull(message, "message");
            Guard.NotNull(asyncLock, "asyncLock");


            using (await asyncLock.LockAsync())            //messageSpecificCancellationTokenSource != null ? messageSpecificCancellationTokenSource.Token : CancellationToken.None))
            {
                // Cancel all other waiting operations before deleting.
                this.Top.DeleteMessage(message.ActualMessage);

                if (await message.GetWasOverflownAsync().ConfigureAwait(false))
                {
                    try
                    {
                        await this.Top.RemoveOverflownContentsAsync(message, messageSpecificCancellationTokenSource.Token).ConfigureAwait(false);
                    }
                    catch (CloudToolsStorageException ex)
                    {
                        if (ex.StatusCode != 404 && ex.StatusCode != 409 && ex.StatusCode != 412)
                        {
                            throw;
                        }
                    }
                }

                if (messageSpecificCancellationTokenSource != null)
                {
                    messageSpecificCancellationTokenSource.Cancel();
                }
            }
        }
        /// <summary>
        ///     Handles poison messages by either delegating it to a handler or deleting it if no handler is provided.
        /// </summary>
        /// <param name="message">The message to operate on.</param>
        /// <param name="messageOptions">Initialisation options for this method.</param>
        /// <param name="asyncLock">An object that's responsible for synchronising access to shared resources in an asynchronous manner.</param>
        /// <param name="messageSpecificCancellationTokenSource">The message-specific cancellation token.</param>
        /// <returns>
        ///     True if the <paramref name="message" /> was deleted; <see langword="false" /> if it should be requeued and <see langword="checked" /> again.
        /// </returns>
        private async Task <bool> WasPoisonMessageAndRemoved(
            [NotNull] HandleMessagesSerialOptions messageOptions,
            [NotNull] QueueMessageWrapper message,
            [NotNull] AsyncLock asyncLock,
            [NotNull] CancellationTokenSource messageSpecificCancellationTokenSource)
        {
            Guard.NotNull(messageOptions, "messageOptions");
            Guard.NotNull(message, "message");
            Guard.NotNull(asyncLock, "asyncLock");
            Guard.NotNull(messageSpecificCancellationTokenSource, "messageSpecificCancellationTokenSource");

            if (message.ActualMessage.DequeueCount <= messageOptions.PoisonMessageThreshold)
            {
                return(false);
            }

            if (messageOptions.PoisonHandler != null && !(await messageOptions.PoisonHandler(message).ConfigureAwait(false)))
            {
                return(false);
            }

            this.Statistics.IncreasePoisonMessages();

            await this.Top.SyncDeleteMessage(asyncLock, message, messageSpecificCancellationTokenSource).ConfigureAwait(false);

            return(true);
        }
        /// <summary>
        ///     This member is intended for internal usage only. Converts an incoming message to an entity.
        /// </summary>
        /// <typeparam name="T">The type of the object to attempt to deserialise to.</typeparam>
        /// <param name="message">The original message.</param>
        /// <param name="token">An optional cancellation token.</param>
        /// <returns>The contents of the message as an instance of type <typeparamref name="T" />.</returns>
        public virtual async Task <T> DecodeMessageAsync <T>(QueueMessageWrapper message, CancellationToken token)
        {
            var msgBytes     = message.ActualMessage.AsBytes;
            var overflownId  = (message.SetOverflowId(await this.Top.GetOverflownMessageId(message.ActualMessage).ConfigureAwait(false)));
            var wasOverflown = (message.SetWasOverflown(!string.IsNullOrWhiteSpace(overflownId)));

            msgBytes = await(wasOverflown
                                ? this.Top.GetOverflownMessageContentsAsync(message.ActualMessage, overflownId, token)
                                : this.Top.GetNonOverflownMessageContentsAsync(message.ActualMessage, token)).ConfigureAwait(false);

            var serialized = await this.Top.ByteArrayToSerializedMessageContents(msgBytes).ConfigureAwait(false);

            return(typeof(T) == typeof(string) ? (T)(object)serialized : this.Top.DeserializeToObject <T>(serialized));
        }
        /// <summary>
        ///     Processes a queue message.
        /// </summary>
        /// <param name="message">The message to be processed.</param>
        /// <param name="messageOptions">Initialisation options for the method that handles the messages.</param>
        /// <param name="messageSpecificCancellationTokenSource">A cancellation token source that's specific to this message.</param>
        /// <param name="asyncLock">An object that's responsible for synchronising access to shared resources in an asynchronous manner.</param>
        private async Task <Task> ProcessMessageInternal(
            [NotNull] QueueMessageWrapper message,
            [NotNull] HandleMessagesSerialOptions messageOptions,
            [NotNull] CancellationTokenSource messageSpecificCancellationTokenSource)
        {
            Guard.NotNull(message, "message");
            Guard.NotNull(messageOptions, "messageOptions");
            Guard.NotNull(messageSpecificCancellationTokenSource, "messageSpecificCancellationTokenSource");

            var asynclock = new AsyncLock();


            // Very old message; delete it and move to the next one
            if (messageOptions.TimeWindow.TotalSeconds > 0 &&
                (!message.ActualMessage.InsertionTime.HasValue || message.ActualMessage.InsertionTime.Value.UtcDateTime.Add(messageOptions.TimeWindow) < DateTime.UtcNow))
            {
                await this.Top.SyncDeleteMessage(asynclock, message, messageSpecificCancellationTokenSource).ConfigureAwait(false);

                return(Task.FromResult <Task>(null));
            }

            // Handles poison messages by either delegating it to a handler or deleting it if no handler is provided.
            if (await this.Top.WasPoisonMessageAndRemoved(messageOptions, message, asynclock, messageSpecificCancellationTokenSource).ConfigureAwait(false))
            {
                return(Task.FromResult <Task>(null));
            }

            // Starts the background thread which ensures message leases stay fresh.
            var keepAliveTask = this.KeepMessageAlive(message.ActualMessage, messageOptions.MessageLeaseTime, messageSpecificCancellationTokenSource.Token, asynclock);

            using (var comboCancelToken = CancellationTokenSource.CreateLinkedTokenSource(messageSpecificCancellationTokenSource.Token, messageOptions.CancelToken))
            {
                // Execute the provided action and if successful, delete the message.
                if (await messageOptions.MessageHandler(message).ConfigureAwait(false))
                {
                    this.Statistics.IncreaseSuccessfulMessages();
                    await this.Top.SyncDeleteMessage(asynclock, message, comboCancelToken).ConfigureAwait(false);
                }
                else
                {
                    this.Statistics.IncreaseReenqueuesCount();
                }
            }


            messageSpecificCancellationTokenSource.Cancel();
            return(keepAliveTask);
        }
 /// <summary>
 /// Cleans up the message contents that were stored outside of the message due to the contents being overflown.
 /// </summary>
 /// <param name="message">The message's contents.</param>
 /// <param name="token">An optional cancellation token.</param>
 protected internal override Task RemoveOverflownContentsAsync(QueueMessageWrapper message, CancellationToken token)
 {
     return(Task.FromResult(false));
 }
 /// <summary>
 /// Cleans up the message contents that were stored outside of the message due to the contents being overflown.
 /// </summary>
 /// <param name="message">The message's contents.</param>
 /// <param name="token">An optional cancellation token.</param>
 protected internal abstract Task RemoveOverflownContentsAsync(QueueMessageWrapper message, CancellationToken token);