public async Task Route(CancellationToken cancellationToken) { if (IsRunning) { throw new InvalidOperationException($"The [{nameof(DefaultMessageRouter)}] is already running."); } else { IsRunning = true; } await foreach (var handlingProcess in _messageReceiver.Receive(cancellationToken)) { Stopwatch stopWatch = null; if (_logger.IsEnabled(LogLevel.Trace)) { stopWatch = new Stopwatch(); stopWatch.Start(); } var messageType = handlingProcess.Message.GetType(); var(handlerDelegate, handlerType) = _messageHandlersRegistry.HandlerDelegateFor(messageType); using var scope = _serviceProvider.CreateScope(); var handler = (IMessageHandler)scope.ServiceProvider.GetService(handlerType); _logger.LogTrace( message: LogMessageHandlingTemplate, Thread.CurrentThread.ManagedThreadId, messageType, handlerType ); // We do busy-waiting instead of Task.Delay because it's cheaper to await on remove/add-misses because they're quick, rather than yield to another thread. var handlerTask = Task.Run(async() => { try { await handler .Handle(handlingProcess.Message, handlerDelegate, cancellationToken) .ConfigureAwait(false); handlingProcess.ToHandled(); } catch (Exception exception) { handlingProcess.ToError(exception); } }).AnywayContinuation(action: task => { // Busy-waiting RunningTask removedTask; while (!_runningTasks.TryRemove(task.Id, out removedTask)) { _spinForRemove.SpinOnce(); } if (_logger.IsEnabled(LogLevel.Trace)) { stopWatch.Stop(); _logger.LogTrace( message: LogMessageRemovedTemplate, removedTask.Name, removedTask.Task.Id, stopWatch.ElapsedMilliseconds ); } }, continueTask: out _, cancellationToken: cancellationToken); // Busy-waiting while (!_runningTasks.TryAdd(handlerTask.Id, new RunningTask(messageType.Name, handlerTask))) { _spinForAdd.SpinOnce(); } _logger.LogTrace( message: LogMessageAddedForHandling, Thread.CurrentThread.ManagedThreadId, messageType.Name, handlerTask.Id ); } }