예제 #1
0
        public Task Initialize()
        {
            _logger.LogConfigurationHeader("Command Handler");

            RecurrentCancellableTask.StartNew(async() => await ParseCommand(Console.ReadLine()?.ToLower()), new TimeSpan(1), _inputTaskTokenSource.Token);

            _logger.LogConfigurationStatus("OK");
            return(Task.CompletedTask);
        }
예제 #2
0
 public Task Start()
 {
     _cancelationTokenSource = new CancellationTokenSource();
     RecurrentCancellableTask.StartNew(async() =>
     {
         var matches = await _client.GetMatchesAsync(_deviceToSubscribe.Id);
         MatchReceived?.Invoke(this, new MatchReceivedEventArgs(_deviceToSubscribe, MatchChannel.Polling, matches));
     },
                                       pollInterval: TimeSpan.FromSeconds(10),
                                       token: _cancelationTokenSource.Token,
                                       taskCreationOptions: TaskCreationOptions.LongRunning);
     return(Task.CompletedTask);
 }
예제 #3
0
        public void Start()
        {
            _locator = CrossGeolocator.Current;
            _cancelationTokenSource = new CancellationTokenSource();
            RecurrentCancellableTask.StartNew(async() =>
            {
                var location = await _locator.GetPositionAsync(TimeSpan.FromSeconds(10), _cancelationTokenSource.Token).ConfigureAwait(false);


                LocationUpdated?.Invoke(this, new LocationUpdatedEventArgs(new Location
                {
                    Longitude = location.Longitude,
                    Altitude  = location.Altitude,
                    Latitude  = location.Latitude
                }));
            }, TimeSpan.FromSeconds(10), _cancelationTokenSource.Token, TaskCreationOptions.LongRunning);
        }
예제 #4
0
        private async Task ProcessMessages(TimeSpan?visibilityTimeout = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            var runningTasks   = new ConcurrentDictionary <Task, Task>();
            var semaphore      = new SemaphoreSlim(_concurrentTasks, _concurrentTasks);
            var queuedMessages = new ConcurrentQueue <CloudMessage>();

            // Define the task that fetches messages from the Azure queue
            RecurrentCancellableTask.StartNew(
                async() =>
            {
                // Fetch messages from the Azure queue when the number of items in the concurrent queue falls below an "acceptable" level.
                if (!cancellationToken.IsCancellationRequested && queuedMessages.Count <= _concurrentTasks / 2)
                {
                    using (_metrics.Measure.Timer.Time(Metrics.MessageFetchingTimer))
                    {
                        IEnumerable <CloudMessage> messages = null;
                        try
                        {
                            messages = await _queueManager.GetMessagesAsync(_concurrentTasks, visibilityTimeout, null, null, cancellationToken).ConfigureAwait(false);
                        }
                        catch (TaskCanceledException)
                        {
                            // The message pump is shutting down.
                            // This exception can be safely ignored.
                        }
                        catch (Exception e)
                        {
                            _logger.InfoException("An error occured while fetching messages from the Azure queue. The error was caught and ignored.", e.GetBaseException());
                        }

                        if (messages == null)
                        {
                            return;
                        }

                        if (messages.Any())
                        {
                            _logger.Trace($"Fetched {messages.Count()} message(s) from the queue.");

                            foreach (var message in messages)
                            {
                                queuedMessages.Enqueue(message);
                            }
                        }
                        else
                        {
                            _logger.Trace("The queue is empty, no messages fetched.");
                            try
                            {
                                // The queue is empty
                                OnQueueEmpty?.Invoke(cancellationToken);
                                _metrics.Measure.Counter.Increment(Metrics.QueueEmptyCounter);
                            }
                            catch (Exception e)
                            {
                                _logger.InfoException("An error occured when handling an empty queue. The error was caught and ignored.", e.GetBaseException());
                            }
                        }
                    }
                }
            },
                TimeSpan.FromMilliseconds(500),
                cancellationToken,
                TaskCreationOptions.LongRunning);

            // Define the task that checks how many messages are queued
            RecurrentCancellableTask.StartNew(
                async() =>
            {
                try
                {
                    var count = await _queueManager.GetApproximateMessageCountAsync(cancellationToken).ConfigureAwait(false);
                    count    += queuedMessages.Count;
                    _metrics.Measure.Gauge.SetValue(Metrics.QueuedMessagesGauge, count);
                }
                catch (TaskCanceledException)
                {
                    // The message pump is shutting down.
                    // This exception can be safely ignored.
                }
                catch (Exception e)
                {
                    _logger.InfoException("An error occured while checking how many message are waiting in the queue. The error was caught and ignored.", e.GetBaseException());
                }
            },
                TimeSpan.FromMilliseconds(5000),
                cancellationToken,
                TaskCreationOptions.LongRunning);

            // Define the task pump
            var pumpTask = Task.Run(async() =>
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);

                    // Retrieved the next message from the queue and process it
                    var runningTask = Task.Run(
                        async() =>
                    {
                        var messageProcessed = false;

                        if (cancellationToken.IsCancellationRequested)
                        {
                            return(messageProcessed);
                        }

                        using (_metrics.Measure.Timer.Time(Metrics.MessageProcessingTimer))
                        {
                            queuedMessages.TryDequeue(out CloudMessage message);

                            if (message != null)
                            {
                                try
                                {
                                    // Process the message
                                    OnMessage?.Invoke(message, cancellationToken);

                                    // Delete the processed message from the queue
                                    // PLEASE NOTE: we use "CancellationToken.None" to ensure a processed message is deleted from the queue even when the message pump is shutting down
                                    await _queueManager.DeleteMessageAsync(message, null, null, CancellationToken.None).ConfigureAwait(false);
                                }
                                catch (Exception ex)
                                {
                                    var isPoison = message.DequeueCount > _maxDequeueCount;
                                    OnError?.Invoke(message, ex, isPoison);
                                    if (isPoison)
                                    {
                                        // PLEASE NOTE: we use "CancellationToken.None" to ensure a processed message is deleted from the queue even when the message pump is shutting down
                                        await _queueManager.DeleteMessageAsync(message, null, null, CancellationToken.None).ConfigureAwait(false);
                                    }
                                }

                                messageProcessed = true;
                            }
                        }

                        // Increment the counter if we processed a message
                        if (messageProcessed)
                        {
                            _metrics.Measure.Counter.Increment(Metrics.MessagesProcessedCounter);
                        }

                        // Return a value indicating whether we processed a message or not
                        return(messageProcessed);
                    },
                        CancellationToken.None);

                    // Add the task to the dictionary of tasks (allows us to keep track of the running tasks)
                    runningTasks.TryAdd(runningTask, runningTask);

                    // Complete the task
                    runningTask.ContinueWith(
                        t =>
                    {
                        semaphore.Release();
                        runningTasks.TryRemove(t, out Task taskToBeRemoved);
                    }, TaskContinuationOptions.ExecuteSynchronously)
                    .IgnoreAwait();
                }
            });

            // Run the task pump until canceled
            await pumpTask.UntilCancelled().ConfigureAwait(false);

            // Task pump has been canceled, wait for the currently running tasks to complete
            await Task.WhenAll(runningTasks.Values).UntilCancelled().ConfigureAwait(false);
        }