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 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)); } }
private async Task RunAsync(CancellationToken cancellationToken) { try { // Allow Start to return immediately without waiting for any initial iteration work to start. await Task.Yield(); Task wait = _initialWait; // Execute tasks one at a time (in a series) until stopped. while (!cancellationToken.IsCancellationRequested) { TaskCompletionSource <object> cancellationTaskSource = new TaskCompletionSource <object>(); using (cancellationToken.Register(() => cancellationTaskSource.SetCanceled())) { try { await Task.WhenAny(wait, cancellationTaskSource.Task); } catch (OperationCanceledException) { // When Stop fires, don't make it wait for wait before it can return. } } if (cancellationToken.IsCancellationRequested) { break; } try { TaskSeriesCommandResult result = await _command.ExecuteAsync(cancellationToken); wait = result.Wait; } catch (OperationCanceledException) { // Don't fail the task, throw a background exception, or stop looping when a 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)); } }