예제 #1
0
 private async Task ReleaseMessageAsync(IStorageQueueMessage message, CancellationToken cancellationToken)
 {
     try
     {
         // We couldn't process the message. Let someone else try.
         await _queue.UpdateMessageAsync(message, TimeSpan.Zero, MessageUpdateFields.Visibility, cancellationToken);
     }
     catch (StorageException exception)
     {
         if (exception.IsBadRequestPopReceiptMismatch())
         {
             // Someone else already took over the message; no need to do anything.
             return;
         }
         else if (exception.IsNotFoundMessageOrQueueNotFound() ||
                  exception.IsConflictQueueBeingDeletedOrDisabled())
         {
             // The message or queue is gone, or the queue is down; no need to release the message.
             return;
         }
         else
         {
             throw;
         }
     }
 }
예제 #2
0
        public void QueueTrigger_ProvidesPocoComplexPropertyBindingData()
        {
            // Arrange
            Poco expectedChild = new Poco
            {
                Value      = "abc",
                Int32Value = 123
            };
            IStorageAccount account = CreateFakeStorageAccount();
            IStorageQueue   queue   = CreateQueue(account, QueueName);
            Poco            value   = new Poco {
                Child = expectedChild
            };
            string content = JsonConvert.SerializeObject(value, typeof(Poco), settings: null);
            IStorageQueueMessage message = queue.CreateMessage(content);

            queue.AddMessage(message);

            // Act
            Poco result = RunTrigger <Poco>(account, typeof(BindToPocoComplexPropertyBindingDataProgram),
                                            (s) => BindToPocoComplexPropertyBindingDataProgram.TaskSource = s);

            // Assert
            AssertEqual(expectedChild, result);
        }
예제 #3
0
        /// <inheritdoc />
        public Task UpdateMessageAsync(IStorageQueueMessage message, TimeSpan visibilityTimeout,
                                       MessageUpdateFields updateFields, CancellationToken cancellationToken)
        {
            CloudQueueMessage sdkMessage = ((StorageQueueMessage)message).SdkObject;

            return(_sdk.UpdateMessageAsync(sdkMessage, visibilityTimeout, updateFields, options: null, operationContext: null, cancellationToken: cancellationToken));
        }
예제 #4
0
 private async Task DeleteMessageAsync(IStorageQueueMessage message, CancellationToken cancellationToken)
 {
     try
     {
         await _queue.DeleteMessageAsync(message, cancellationToken);
     }
     catch (StorageException exception)
     {
         // For consistency, the exceptions handled here should match UpdateQueueMessageVisibilityCommand.
         if (exception.IsBadRequestPopReceiptMismatch())
         {
             // If someone else took over the message; let them delete it.
             return;
         }
         else if (exception.IsNotFoundMessageOrQueueNotFound() ||
                  exception.IsConflictQueueBeingDeletedOrDisabled())
         {
             // The message or queue is gone, or the queue is down; no need to delete the message.
             return;
         }
         else
         {
             throw;
         }
     }
 }
        public void ExecuteAsync_IfMessageIsFunctionIdIsRegistered_GetsETag(BlobType expectedBlobType)
        {
            // Arrange
            string expectedContainerName = "container";
            string expectedBlobName      = TestBlobName;
            string functionId            = "FunctionId";
            Mock <IBlobETagReader> mock  = new Mock <IBlobETagReader>(MockBehavior.Strict);

            mock.Setup(r => r.GetETagAsync(It.Is <IStorageBlob>(b => b.BlobType == (StorageBlobType)expectedBlobType &&
                                                                b.Name == expectedBlobName && b.Container.Name == expectedContainerName),
                                           It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult("ETag"))
            .Verifiable();
            IBlobETagReader          eTagReader = mock.Object;
            BlobQueueTriggerExecutor product    = CreateProductUnderTest(eTagReader);

            product.Register(functionId, CreateDummyTriggeredFunctionExecutor());

            BlobTriggerMessage triggerMessage = new BlobTriggerMessage
            {
                FunctionId    = functionId,
                BlobType      = (StorageBlobType)expectedBlobType,
                ContainerName = expectedContainerName,
                BlobName      = expectedBlobName,
                ETag          = "OriginalETag"
            };
            IStorageQueueMessage message = CreateMessage(triggerMessage);

            // Act
            Task task = product.ExecuteAsync(message, CancellationToken.None);

            // Assert
            task.WaitUntilCompleted();
            mock.Verify();
        }
        public static Guid? GetOwner(IStorageQueueMessage msg)
        {
            string text = msg.TryGetAsString();

            if (text == null)
            {
                return null;
            }

            IDictionary<string, JToken> json;
            try
            {
                json = JsonSerialization.ParseJObject(text);
            }
            catch (Exception)
            {
                return null;
            }

            if (!json.ContainsKey(ParentGuidFieldName) || json[ParentGuidFieldName].Type != JTokenType.String)
            {
                return null;
            }

            string val = (string)json[ParentGuidFieldName];

            Guid guid;
            if (Guid.TryParse(val, out guid))
            {
                return guid;
            }
            return null;
        }
예제 #7
0
        public static async Task AddMessageAndCreateIfNotExistsAsync(this IStorageQueue queue,
                                                                     IStorageQueueMessage message, CancellationToken cancellationToken)
        {
            if (queue == null)
            {
                throw new ArgumentNullException("queue");
            }

            bool isQueueNotFoundException = false;

            try
            {
                await queue.AddMessageAsync(message, cancellationToken);

                return;
            }
            catch (StorageException exception)
            {
                if (!exception.IsNotFoundQueueNotFound())
                {
                    throw;
                }

                isQueueNotFoundException = true;
            }

            Debug.Assert(isQueueNotFoundException);
            await queue.CreateIfNotExistsAsync(cancellationToken);

            await queue.AddMessageAsync(message, cancellationToken);
        }
예제 #8
0
        public void QueueTrigger_IfBoundToPocoAndMessageIsNotJson_DoesNotBind()
        {
            // Arrange
            const string         content = "not json"; // Not a valid JSON byte sequence.
            IStorageAccount      account = CreateFakeStorageAccount();
            IStorageQueue        queue   = CreateQueue(account, QueueName);
            IStorageQueueMessage message = queue.CreateMessage(content);

            queue.AddMessage(message);

            // Act
            Exception exception = RunTriggerFailure <Poco>(account, typeof(BindToPocoProgram),
                                                           (s) => BindToPocoProgram.TaskSource = s);

            // Assert
            Assert.IsType <InvalidOperationException>(exception);
            Assert.Equal("Exception binding parameter 'message'", exception.Message);
            Exception innerException = exception.InnerException;

            Assert.IsType <InvalidOperationException>(innerException);
            const string expectedInnerMessage = "Binding parameters to complex objects (such as 'Poco') uses " +
                                                "Json.NET serialization. \r\n1. Bind the parameter type as 'string' instead of 'Poco' to get the raw " +
                                                "values and avoid JSON deserialization, or\r\n2. Change the queue payload to be valid json. The JSON " +
                                                "parser failed: Unexpected character encountered while parsing value: n. Path '', line 0, position " +
                                                "0.\r\n";

            Assert.Equal(expectedInnerMessage, innerException.Message);
        }
예제 #9
0
        public static string TryGetAsString(this IStorageQueueMessage message)
        {
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }

            string value;

            try
            {
                value = message.AsString;
            }
            catch (Exception ex)
            {
                if (ex is DecoderFallbackException || ex is FormatException)
                {
                    value = null;
                }
                else
                {
                    throw;
                }
            }

            return(value);
        }
        public void ExecuteAsync_IfBlobIsUnchanged_CallsInnerExecutor()
        {
            // Arrange
            string                   functionId       = "FunctionId";
            string                   matchingETag     = "ETag";
            Guid                     expectedParentId = Guid.NewGuid();
            IBlobETagReader          eTagReader       = CreateStubETagReader(matchingETag);
            IBlobCausalityReader     causalityReader  = CreateStubCausalityReader(expectedParentId);
            Mock <IFunctionExecutor> mock             = new Mock <IFunctionExecutor>(MockBehavior.Strict);

            mock.Setup(e => e.TryExecuteAsync(It.Is <IFunctionInstance>(f => f.ParentId == expectedParentId),
                                              It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult <IDelayedException>(null))
            .Verifiable();
            IFunctionExecutor        innerExecutor = mock.Object;
            BlobQueueTriggerExecutor product       = CreateProductUnderTest(eTagReader, causalityReader, innerExecutor);

            product.Register(functionId, CreateFakeInstanceFactory());

            IStorageQueueMessage message = CreateMessage(functionId, matchingETag);

            // Act
            Task <bool> task = product.ExecuteAsync(message, CancellationToken.None);

            // Assert
            task.WaitUntilCompleted();
            mock.Verify();
        }
예제 #11
0
        public void QueueTrigger_IfBoundToPocoAndMessageIsIncompatibleJson_DoesNotBind()
        {
            // Arrange
            const string         content = "123"; // A JSON int rather than a JSON object.
            IStorageAccount      account = CreateFakeStorageAccount();
            IStorageQueue        queue   = CreateQueue(account, QueueName);
            IStorageQueueMessage message = queue.CreateMessage(content);

            queue.AddMessage(message);

            // Act
            Exception exception = RunTriggerFailure <Poco>(account, typeof(BindToPocoProgram),
                                                           (s) => BindToPocoProgram.TaskSource = s);

            // Assert
            Assert.IsType <InvalidOperationException>(exception);
            Assert.Equal("Exception binding parameter 'message'", exception.Message);
            Exception innerException = exception.InnerException;

            Assert.IsType <InvalidOperationException>(innerException);
            string expectedInnerMessage = "Binding parameters to complex objects (such as 'Poco') uses Json.NET " +
                                          "serialization. \r\n1. Bind the parameter type as 'string' instead of 'Poco' to get the raw values " +
                                          "and avoid JSON deserialization, or\r\n2. Change the queue payload to be valid json. The JSON parser " +
                                          "failed: Error converting value 123 to type '" + typeof(Poco).FullName + "'. Path '', line 1, " +
                                          "position 3.\r\n";

            Assert.Equal(expectedInnerMessage, innerException.Message);
        }
        public static async Task AddMessageAndCreateIfNotExistsAsync(this IStorageQueue queue,
            IStorageQueueMessage message, CancellationToken cancellationToken)
        {
            if (queue == null)
            {
                throw new ArgumentNullException("queue");
            }

            bool isQueueNotFoundException = false;

            try
            {
                await queue.AddMessageAsync(message, cancellationToken);
                return;
            }
            catch (StorageException exception)
            {
                if (!exception.IsNotFoundQueueNotFound())
                {
                    throw;
                }

                isQueueNotFoundException = true;
            }

            Debug.Assert(isQueueNotFoundException);
            await queue.CreateIfNotExistsAsync(cancellationToken);
            await queue.AddMessageAsync(message, cancellationToken);
        }
        public void ExecuteAsync_IfBlobHasChanged_NotifiesWatcherAndReturnsSuccessResult()
        {
            // Arrange
            string                     functionId = "FunctionId";
            IBlobETagReader            eTagReader = CreateStubETagReader("NewETag");
            Mock <IBlobWrittenWatcher> mock       = new Mock <IBlobWrittenWatcher>(MockBehavior.Strict);

            mock.Setup(w => w.Notify(It.IsAny <IStorageBlob>()))
            .Verifiable();
            IBlobWrittenWatcher      blobWrittenWatcher = mock.Object;
            BlobQueueTriggerExecutor product            = CreateProductUnderTest(eTagReader, blobWrittenWatcher);

            BlobQueueRegistration registration = new BlobQueueRegistration
            {
                BlobClient = CreateClient(),
                Executor   = CreateDummyTriggeredFunctionExecutor()
            };

            product.Register(functionId, registration);

            IStorageQueueMessage message = CreateMessage(functionId, "OriginalETag");

            // Act
            Task <FunctionResult> task = product.ExecuteAsync(message, CancellationToken.None);

            // Assert
            task.WaitUntilCompleted();
            mock.Verify();
            Assert.True(task.Result.Succeeded);
        }
예제 #14
0
        public static Guid?GetOwner(IStorageQueueMessage msg)
        {
            string text = msg.TryGetAsString();

            if (text == null)
            {
                return(null);
            }

            IDictionary <string, JToken> json;

            try
            {
                json = JsonSerialization.ParseJObject(text);
            }
            catch (Exception)
            {
                return(null);
            }

            if (!json.ContainsKey(ParentGuidFieldName) || json[ParentGuidFieldName].Type != JTokenType.String)
            {
                return(null);
            }

            string val = (string)json[ParentGuidFieldName];

            Guid guid;

            if (Guid.TryParse(val, out guid))
            {
                return(guid);
            }
            return(null);
        }
        public void ExecuteAsync_IfInnerExecutorFails_ReturnsFailureResult()
        {
            // Arrange
            string               functionId      = "FunctionId";
            string               matchingETag    = "ETag";
            IBlobETagReader      eTagReader      = CreateStubETagReader(matchingETag);
            IBlobCausalityReader causalityReader = CreateStubCausalityReader();

            FunctionResult expectedResult          = new FunctionResult(false);
            Mock <ITriggeredFunctionExecutor> mock = new Mock <ITriggeredFunctionExecutor>(MockBehavior.Strict);

            mock.Setup(e => e.TryExecuteAsync(
                           It.IsAny <TriggeredFunctionData>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(expectedResult)
            .Verifiable();

            BlobQueueTriggerExecutor product = CreateProductUnderTest(eTagReader, causalityReader);

            ITriggeredFunctionExecutor innerExecutor = mock.Object;

            product.Register(functionId, innerExecutor);

            IStorageQueueMessage message = CreateMessage(functionId, matchingETag);

            // Act
            Task <FunctionResult> task = product.ExecuteAsync(message, CancellationToken.None);

            // Assert
            Assert.False(task.Result.Succeeded);
        }
        internal async Task ProcessMessageAsync(IStorageQueueMessage message, TimeSpan visibilityTimeout, CancellationToken cancellationToken)
        {
            try
            {
                if (!await _queueProcessor.BeginProcessingMessageAsync(message.SdkObject, cancellationToken))
                {
                    return;
                }

                FunctionResult result = null;
                using (ITaskSeriesTimer timer = CreateUpdateMessageVisibilityTimer(_queue, message, visibilityTimeout, _backgroundExceptionDispatcher))
                {
                    timer.Start();

                    result = await _triggerExecutor.ExecuteAsync(message, cancellationToken);

                    await timer.StopAsync(cancellationToken);
                }

                await _queueProcessor.CompleteProcessingMessageAsync(message.SdkObject, result, cancellationToken);
            }
            catch (OperationCanceledException)
            {
                // Don't fail the top-level task when an inner task cancels.
            }
            catch (Exception exception)
            {
                // Immediately report any unhandled exception from this background task.
                // (Don't capture the exception as a fault of this Task; that would delay any exception reporting until
                // Stop is called, which might never happen.)
                _backgroundExceptionDispatcher.Throw(ExceptionDispatchInfo.Capture(exception));
            }
        }
        private static IReadOnlyDictionary <string, object> CreateBindingData(IStorageQueueMessage value,
                                                                              IReadOnlyDictionary <string, object> bindingDataFromValueType)
        {
            Dictionary <string, object> bindingData = new Dictionary <string, object>(StringComparer.OrdinalIgnoreCase);

            string queueMessageString = value.TryGetAsString();

            // Don't provide the QueueTrigger binding data when the queue message is not a valid string.
            if (queueMessageString != null)
            {
                bindingData.Add("QueueTrigger", queueMessageString);
            }

            bindingData.Add("DequeueCount", value.DequeueCount);
            bindingData.Add("ExpirationTime", value.ExpirationTime.GetValueOrDefault(DateTimeOffset.MaxValue));
            bindingData.Add("Id", value.Id);
            bindingData.Add("InsertionTime", value.InsertionTime.GetValueOrDefault(DateTimeOffset.UtcNow));
            bindingData.Add("NextVisibleTime", value.NextVisibleTime.GetValueOrDefault(DateTimeOffset.MaxValue));
            bindingData.Add("PopReceipt", value.PopReceipt);

            if (bindingDataFromValueType != null)
            {
                foreach (KeyValuePair <string, object> item in bindingDataFromValueType)
                {
                    // In case of conflict, binding data from the value type overrides the built-in binding data above.
                    bindingData[item.Key] = item.Value;
                }
            }

            return(bindingData);
        }
예제 #18
0
        private static void TestOwnerIsNull(IStorageQueueMessage message)
        {
            // Act
            Guid?owner = QueueCausalityManager.GetOwner(message);

            // Assert
            Assert.Null(owner);
        }
        public static void AddMessage(this IStorageQueue queue, IStorageQueueMessage message)
        {
            if (queue == null)
            {
                throw new ArgumentNullException("queue");
            }

            queue.AddMessageAsync(message, CancellationToken.None).GetAwaiter().GetResult();
        }
예제 #20
0
        public void GetOwner_IfMessageIsNotValidString_ReturnsNull()
        {
            Mock <IStorageQueueMessage> mock = new Mock <IStorageQueueMessage>(MockBehavior.Strict);

            mock.Setup(m => m.AsString).Throws <DecoderFallbackException>();
            IStorageQueueMessage message = mock.Object;

            TestOwnerIsNull(message);
        }
예제 #21
0
        public static void AddMessage(this IStorageQueue queue, IStorageQueueMessage message)
        {
            if (queue == null)
            {
                throw new ArgumentNullException("queue");
            }

            queue.AddMessageAsync(message, CancellationToken.None).GetAwaiter().GetResult();
        }
예제 #22
0
        private async Task CopyToPoisonQueueAsync(IStorageQueueMessage message, CancellationToken cancellationToken)
        {
            await _poisonQueue.AddMessageAndCreateIfNotExistsAsync(message, cancellationToken);

            if (_sharedWatcher != null)
            {
                _sharedWatcher.Notify(_poisonQueue.Name);
            }
        }
예제 #23
0
        private async Task ProcessMessageAsync(IStorageQueueMessage message, TimeSpan visibilityTimeout,
                                               CancellationToken cancellationToken)
        {
            try
            {
                bool succeeded;

                using (ITaskSeriesTimer timer = CreateUpdateMessageVisibilityTimer(_queue, message, visibilityTimeout,
                                                                                   _backgroundExceptionDispatcher))
                {
                    timer.Start();

                    succeeded = await _triggerExecutor.ExecuteAsync(message, cancellationToken);

                    await timer.StopAsync(cancellationToken);
                }

                // Need to call Delete message only if function succeeded.
                if (succeeded)
                {
                    await DeleteMessageAsync(message, cancellationToken);
                }
                else if (_poisonQueue != null)
                {
                    if (message.DequeueCount >= _maxDequeueCount)
                    {
                        _log.WriteLine("Message has reached MaxDequeueCount of {0}. Moving message to queue '{1}'.",
                                       _maxDequeueCount,
                                       _poisonQueue.Name);
                        await CopyToPoisonQueueAsync(message, cancellationToken);
                        await DeleteMessageAsync(message, cancellationToken);
                    }
                    else
                    {
                        await ReleaseMessageAsync(message, cancellationToken);
                    }
                }
                else
                {
                    // For queues without a corresponding poison queue, leave the message invisible when processing
                    // fails to prevent a fast infinite loop.
                    // Specifically, don't call ReleaseMessage(message)
                }
            }
            catch (OperationCanceledException)
            {
                // Don't fail the top-level task when an inner task cancels.
            }
            catch (Exception exception)
            {
                // Immediately report any unhandled exception from this background task.
                // (Don't capture the exception as a fault of this Task; that would delay any exception reporting until
                // Stop is called, which might never happen.)
                _backgroundExceptionDispatcher.Throw(ExceptionDispatchInfo.Capture(exception));
            }
        }
        public QueueMessageValueProvider(IStorageQueueMessage message, object value, Type valueType)
        {
            if (value != null && !valueType.IsAssignableFrom(value.GetType()))
            {
                throw new InvalidOperationException("value is not of the correct type.");
            }

            _message   = message;
            _value     = value;
            _valueType = valueType;
        }
        public void Add(T item)
        {
            IStorageQueueMessage message = _converter.Convert(item);

            if (message == null)
            {
                throw new InvalidOperationException("Cannot enqueue a null queue message instance.");
            }

            _queue.AddMessageAndCreateIfNotExistsAsync(message, CancellationToken.None).GetAwaiter().GetResult();
        }
예제 #26
0
        public Task AddAsync(T item, CancellationToken cancellationToken)
        {
            IStorageQueueMessage message = _converter.Convert(item);

            if (message == null)
            {
                throw new InvalidOperationException("Cannot enqueue a null queue message instance.");
            }

            return(_queue.AddMessageAndCreateIfNotExistsAsync(message, cancellationToken));
        }
        public QueueMessageValueProvider(IStorageQueueMessage message, object value, Type valueType)
        {
            if (value != null && !valueType.IsAssignableFrom(value.GetType()))
            {
                throw new InvalidOperationException("value is not of the correct type.");
            }

            _message = message;
            _value = value;
            _valueType = valueType;
        }
        public void ExecuteAsync_IfFunctionIdIsNull_Throws()
        {
            // Arrange
            BlobQueueTriggerExecutor product = CreateProductUnderTest();
            IStorageQueueMessage     message = CreateMessage("{}");

            // Act
            Task task = product.ExecuteAsync(message, CancellationToken.None);

            // Assert
            ExceptionAssert.ThrowsInvalidOperation(() => task.GetAwaiter().GetResult(), "Invalid function ID.");
        }
        public async Task SetValueAsync(object value, CancellationToken cancellationToken)
        {
            IStorageQueueMessage message = _converter.Convert((TInput)value);

            Debug.Assert(message != null);
            await _queue.AddMessageAndCreateIfNotExistsAsync(message, cancellationToken);

            if (_messageEnqueuedWatcher != null)
            {
                _messageEnqueuedWatcher.Notify(_queue.Name);
            }
        }
예제 #30
0
        private ITaskSeriesTimer CreateUpdateMessageVisibilityTimer(IStorageQueue queue,
                                                                    IStorageQueueMessage message, TimeSpan visibilityTimeout,
                                                                    IWebJobsExceptionHandler exceptionHandler)
        {
            // Update a message's visibility when it is halfway to expiring.
            TimeSpan normalUpdateInterval = new TimeSpan(visibilityTimeout.Ticks / 2);

            IDelayStrategy     speedupStrategy = new LinearSpeedupStrategy(normalUpdateInterval, MinimumVisibilityRenewalInterval);
            ITaskSeriesCommand command         = new UpdateQueueMessageVisibilityCommand(queue, message, visibilityTimeout, speedupStrategy);

            return(new TaskSeriesTimer(command, exceptionHandler, Task.Delay(normalUpdateInterval)));
        }
        private static ITaskSeriesTimer CreateUpdateMessageVisibilityTimer(IStorageQueue queue,
                                                                           IStorageQueueMessage message, TimeSpan visibilityTimeout,
                                                                           IBackgroundExceptionDispatcher backgroundExceptionDispatcher)
        {
            // Update a message's visibility when it is halfway to expiring.
            TimeSpan normalUpdateInterval = new TimeSpan(visibilityTimeout.Ticks / 2);

            IDelayStrategy     speedupStrategy = new LinearSpeedupStrategy(normalUpdateInterval, TimeSpan.FromMinutes(1));
            ITaskSeriesCommand command         = new UpdateQueueMessageVisibilityCommand(queue, message, visibilityTimeout, speedupStrategy);

            return(new TaskSeriesTimer(command, backgroundExceptionDispatcher, Task.Delay(normalUpdateInterval)));
        }
        public void ExecuteAsync_IfMessageIsNotJson_Throws()
        {
            // Arrange
            BlobQueueTriggerExecutor product = CreateProductUnderTest();
            IStorageQueueMessage     message = CreateMessage("ThisIsNotValidJson");

            // Act
            Task task = product.ExecuteAsync(message, CancellationToken.None);

            // Assert
            Assert.Throws <JsonReaderException>(() => task.GetAwaiter().GetResult());
        }
예제 #33
0
        public bool TryConvert(object input, out IStorageQueueMessage output)
        {
            TInput typedInput = input as TInput;

            if (typedInput == null)
            {
                output = null;
                return(false);
            }

            output = _innerConverter.Convert(typedInput);
            return(true);
        }
        public void ExecuteAsync_IfMessageIsFunctionIdIsNotRegistered_ReturnsSuccessResult()
        {
            // Arrange
            BlobQueueTriggerExecutor product = CreateProductUnderTest();
            IStorageQueueMessage     message = CreateMessage(new BlobTriggerMessage {
                FunctionId = "Missing"
            });

            // Act
            Task <FunctionResult> task = product.ExecuteAsync(message, CancellationToken.None);

            // Assert
            Assert.True(task.Result.Succeeded);
        }
        public Task AddMessageAsync(IStorageQueueMessage message, CancellationToken cancellationToken)
        {
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }

            MutableStorageQueueMessage storeMessage = message as MutableStorageQueueMessage;

            if (storeMessage == null)
            {
                storeMessage = new FakeStorageQueueMessage(message.SdkObject);
            }

            _store.AddMessage(_queueName, storeMessage);
            return Task.FromResult(0);
        }
        public UpdateQueueMessageVisibilityCommand(IStorageQueue queue, IStorageQueueMessage message,
            TimeSpan visibilityTimeout, IDelayStrategy speedupStrategy)
        {
            if (queue == null)
            {
                throw new ArgumentNullException("queue");
            }

            if (message == null)
            {
                throw new ArgumentNullException("message");
            }

            if (speedupStrategy == null)
            {
                throw new ArgumentNullException("speedupStrategy");
            }

            _queue = queue;
            _message = message;
            _visibilityTimeout = visibilityTimeout;
            _speedupStrategy = speedupStrategy;
        }
        private static void TestOwnerIsNull(IStorageQueueMessage message)
        {
            // Act
            Guid? owner = QueueCausalityManager.GetOwner(message);

            // Assert
            Assert.Null(owner);
        }
 /// <inheritdoc />
 public Task DeleteMessageAsync(IStorageQueueMessage message, CancellationToken cancellationToken)
 {
     CloudQueueMessage sdkMessage = ((StorageQueueMessage)message).SdkObject;
     return _sdk.DeleteMessageAsync(sdkMessage, cancellationToken);
 }
 /// <inheritdoc />
 public Task UpdateMessageAsync(IStorageQueueMessage message, TimeSpan visibilityTimeout,
     MessageUpdateFields updateFields, CancellationToken cancellationToken)
 {
     CloudQueueMessage sdkMessage = ((StorageQueueMessage)message).SdkObject;
     return _sdk.UpdateMessageAsync(sdkMessage, visibilityTimeout, updateFields, cancellationToken);
 }
        private static IReadOnlyDictionary<string, object> CreateBindingData(IStorageQueueMessage value,
            IReadOnlyDictionary<string, object> bindingDataFromValueType)
        {
            Dictionary<string, object> bindingData = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);

            string queueMessageString = value.TryGetAsString();

            // Don't provide the QueueTrigger binding data when the queue message is not a valid string.
            if (queueMessageString != null)
            {
                bindingData.Add("QueueTrigger", queueMessageString);
            }

            bindingData.Add("DequeueCount", value.DequeueCount);
            bindingData.Add("ExpirationTime", value.ExpirationTime.GetValueOrDefault(DateTimeOffset.MaxValue));
            bindingData.Add("Id", value.Id);
            bindingData.Add("InsertionTime", value.InsertionTime.GetValueOrDefault(DateTimeOffset.UtcNow));
            bindingData.Add("NextVisibleTime", value.NextVisibleTime.GetValueOrDefault(DateTimeOffset.MaxValue));
            bindingData.Add("PopReceipt", value.PopReceipt);
            
            if (bindingDataFromValueType != null)
            {
                foreach (KeyValuePair<string, object> item in bindingDataFromValueType)
                {
                    // In case of conflict, binding data from the value type overrides the built-in binding data above.
                    bindingData[item.Key] = item.Value;
                }
            }

            return bindingData;
        }
        internal async Task ProcessMessageAsync(IStorageQueueMessage message, TimeSpan visibilityTimeout, CancellationToken cancellationToken)
        {
            try
            {
                if (!await _queueProcessor.BeginProcessingMessageAsync(message.SdkObject, cancellationToken))
                {
                    return;
                }

                FunctionResult result = null;
                using (ITaskSeriesTimer timer = CreateUpdateMessageVisibilityTimer(_queue, message, visibilityTimeout, _backgroundExceptionDispatcher))
                {
                    timer.Start();

                    result = await _triggerExecutor.ExecuteAsync(message, cancellationToken);

                    await timer.StopAsync(cancellationToken);
                }

                await _queueProcessor.CompleteProcessingMessageAsync(message.SdkObject, result, cancellationToken);
            }
            catch (OperationCanceledException)
            {
                // Don't fail the top-level task when an inner task cancels.
            }
            catch (Exception exception)
            {
                // Immediately report any unhandled exception from this background task.
                // (Don't capture the exception as a fault of this Task; that would delay any exception reporting until
                // Stop is called, which might never happen.)
                _backgroundExceptionDispatcher.Throw(ExceptionDispatchInfo.Capture(exception));
            }
        }
        private static ITaskSeriesTimer CreateUpdateMessageVisibilityTimer(IStorageQueue queue,
            IStorageQueueMessage message, TimeSpan visibilityTimeout,
            IBackgroundExceptionDispatcher backgroundExceptionDispatcher)
        {
            // Update a message's visibility when it is halfway to expiring.
            TimeSpan normalUpdateInterval = new TimeSpan(visibilityTimeout.Ticks / 2);

            IDelayStrategy speedupStrategy = new LinearSpeedupStrategy(normalUpdateInterval, TimeSpan.FromMinutes(1));
            ITaskSeriesCommand command = new UpdateQueueMessageVisibilityCommand(queue, message, visibilityTimeout, speedupStrategy);
            return new TaskSeriesTimer(command, backgroundExceptionDispatcher, Task.Delay(normalUpdateInterval));
        }
 public Task UpdateMessageAsync(IStorageQueueMessage message, TimeSpan visibilityTimeout,
     MessageUpdateFields updateFields, CancellationToken cancellationToken)
 {
     _store.UpdateMessage(_queueName, (MutableStorageQueueMessage)message, visibilityTimeout, updateFields);
     return Task.FromResult(0);
 }
 public Task DeleteMessageAsync(IStorageQueueMessage message, CancellationToken cancellationToken)
 {
     _store.DeleteMessage(_queueName, (MutableStorageQueueMessage)message);
     return Task.FromResult(0);
 }