async Task TryProcessNextMessage() { var parallelOperation = _parallelOperationsManager.TryBegin(); if (!parallelOperation.CanContinue()) { await _backoffStrategy.WaitAsync(_cancellationToken); return; } try { using (parallelOperation) using (var context = new TransactionContextWithOwningBus(_owningBus)) { var transportMessage = await ReceiveTransportMessage(_cancellationToken, context); if (transportMessage == null) { context.Dispose(); // get out quickly if we're shutting down if (_cancellationToken.IsCancellationRequested || _busDisposalCancellationToken.IsCancellationRequested) { return; } // no need for another thread to rush in and discover that there is no message //parallelOperation.Dispose(); await _backoffStrategy.WaitNoMessageAsync(_cancellationToken); return; } _backoffStrategy.Reset(); try { AmbientTransactionContext.SetCurrent(context); await ProcessMessage(context, transportMessage); } finally { AmbientTransactionContext.SetCurrent(null); } } } catch (OperationCanceledException) when(_cancellationToken.IsCancellationRequested || _busDisposalCancellationToken.IsCancellationRequested) { // we're shutting down } catch (Exception exception) { _log.Error(exception, "Unhandled exception in worker {workerName}", Name); } }
async Task SendTransportMessage(string destinationAddress, TransportMessage transportMessage) { var transactionContext = GetCurrentTransactionContext(mustBelongToThisBus: true); if (transactionContext == null) { using (var context = new TransactionContextWithOwningBus(this)) { await _transport.Send(destinationAddress, transportMessage, context); await context.Complete(); } } else { await _transport.Send(destinationAddress, transportMessage, transactionContext); } }
async Task InnerSend(IEnumerable <string> destinationAddresses, Message logicalMessage) { var currentTransactionContext = GetCurrentTransactionContext(mustBelongToThisBus: true); if (currentTransactionContext != null) { await SendUsingTransactionContext(destinationAddresses, logicalMessage, currentTransactionContext); } else { using (var context = new TransactionContextWithOwningBus(this)) { await SendUsingTransactionContext(destinationAddresses, logicalMessage, context); await context.Complete(); } } }
async Task TryAsyncReceive(CancellationToken token, IDisposable parallelOperation) { try { using (parallelOperation) using (var context = new TransactionContextWithOwningBus(_owningBus)) { var transportMessage = await ReceiveTransportMessage(token, context); if (transportMessage == null) { context.Dispose(); // get out quickly if we're shutting down if (token.IsCancellationRequested) { return; } // no need for another thread to rush in and discover that there is no message //parallelOperation.Dispose(); await _backoffStrategy.WaitNoMessageAsync(token); return; } _backoffStrategy.Reset(); await ProcessMessage(context, transportMessage); } } catch (OperationCanceledException) when(token.IsCancellationRequested || _busDisposalCancellationToken.IsCancellationRequested) { // it's fine - just a sign that we are shutting down } catch (Exception exception) { _log.Error(exception, "Unhandled exception in worker {workerName}", Name); } }
protected override async Task <int> DoWork(bool isPrimaryReader, CancellationToken token) { int cnt = 0; TransportMessage message = null; TransactionContext context; IDisposable disposable = null; if (this.Coordinator.AsyncReadThrottling) { // better when the reads are slow like from SqlServerTransport disposable = await this.Coordinator.ReadThrottleAsync(isPrimaryReader); } else { // synchronous is better when the reads are fast like from the InMemoryTransport var waitResult = this.Coordinator.ReadThrottle(isPrimaryReader); // if synchronous waiting resulted in timeout (50 milliseconds by default) then wait asynchronously if (!waitResult.Result && !token.IsCancellationRequested) { disposable = await this.Coordinator.ReadThrottleAsync(isPrimaryReader); } else { disposable = waitResult; } } try { token.ThrowIfCancellationRequested(); context = new TransactionContextWithOwningBus(_owningBus); } catch { disposable.Dispose(); throw; } using (context) { try { message = await this.ReadMessage(isPrimaryReader, this.taskId, token, context).ConfigureAwait(false); } finally { disposable.Dispose(); } cnt = message == null ? 0 : 1; if (cnt == 0) { context.Dispose(); if (isPrimaryReader) { await _backoffStrategy.WaitNoMessageAsync(token); } return(0); } _backoffStrategy.Reset(); this.Coordinator.OnBeforeDoWork(this); try { await ProcessMessage(context, message); } finally { this.Coordinator.OnAfterDoWork(this); } } // using Transaction Context return(cnt); }