async void TryReceiveNewMessage() { using (var operation = _parallelOperationsManager.TryBegin()) { // if we didn't get to do our thing, pause the thread a very short while to avoid thrashing too much if (!operation.CanContinue()) { Thread.Sleep(10); return; } using (var transactionContext = new DefaultTransactionContext()) { AmbientTransactionContext.Current = transactionContext; try { var message = await TryReceiveTransportMessage(transactionContext); if (message == null) { // no message: finish the tx and wait.... await transactionContext.Complete(); await _backoffStrategy.Wait(); return; } // we got a message, so we reset the backoff strategy _backoffStrategy.Reset(); var context = new IncomingStepContext(message, transactionContext); var stagedReceiveSteps = _pipeline.ReceivePipeline(); await _pipelineInvoker.Invoke(context, stagedReceiveSteps); try { await transactionContext.Complete(); } catch (Exception exception) { _log.Error(exception, "An error occurred when attempting to complete the transaction context"); } } catch (Exception exception) { // we should not end up here unless something is off.... _log.Error(exception, "Unhandled exception in thread worker - the pipeline didn't handle its own errors (this is bad)"); Thread.Sleep(100); } finally { AmbientTransactionContext.Current = null; } } } }
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); } }
private async Task ProcessOutboxMessages() { _log.Debug("Starting outbox messages processor"); while (!_busDisposalCancellationToken.IsCancellationRequested) { try { bool waitForMessages; using (var transactionScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) { var messages = await _outboxStorage.Retrieve(_busDisposalCancellationToken, _topMessagesToRetrieve); if (messages.Length > 0) { using (var rebusTransactionScope = new RebusTransactionScope()) { foreach (var message in messages) { var destinationAddress = message.Headers[OutboxHeaders.Recipient]; message.Headers.Remove(OutboxHeaders.Recipient); await _transport.Send(destinationAddress, message, rebusTransactionScope.TransactionContext); } await rebusTransactionScope.CompleteAsync(); } waitForMessages = false; } else { waitForMessages = true; } transactionScope.Complete(); } if (waitForMessages) { await _backoffStrategy.WaitNoMessageAsync(_busDisposalCancellationToken); } else { _backoffStrategy.Reset(); } } catch (OperationCanceledException) when(_busDisposalCancellationToken.IsCancellationRequested) { // we're shutting down } catch (Exception exception) { _log.Error(exception, "Unhandled exception in outbox messages processor"); await _backoffStrategy.WaitErrorAsync(_busDisposalCancellationToken); } } _log.Debug("Outbox messages processor stopped"); }
private async Task _processOutboxMessages(CancellationToken ctk) { _log.Debug("Starting outbox messages processor"); while (!ctk.IsCancellationRequested) { try { bool waitForMessages = true; using (var ctx = _outboxContextFactory.Create()) { var messages = await ctx.PeekLockMessagesAsync(_topMessagesToRetrieve, ctk); if (messages.Any()) { using (var rebusTransactionScope = new RebusTransactionScope()) { foreach (var message in messages) { var destinationAddress = message.Headers[OutboxTransportDecorator._outboxRecepientHeader]; message.Headers.Remove(OutboxTransportDecorator._outboxRecepientHeader); await _transport.Send(destinationAddress, new TransportMessage(message.Headers, message.Body), rebusTransactionScope.TransactionContext).WithCancellation(ctk); } await rebusTransactionScope.CompleteAsync().WithCancellation(ctk); } waitForMessages = false; _backoffStrategy.Reset(); } ctx.Commit(); } if (waitForMessages) { await _backoffStrategy.WaitNoMessageAsync(ctk); } } catch (OperationCanceledException) when(ctk.IsCancellationRequested) { // we're shutting down } catch (Exception exception) { _log.Error(exception, "Unhandled exception in outbox messages processor"); await _backoffStrategy.WaitErrorAsync(ctk); } } _log.Debug("Outbox messages processor stopped"); }
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); } }
async void TryReceiveNewMessage() { using (var operation = _parallelOperationsManager.TryBegin()) { // if we didn't get to do our thing, let the OS decide what to do next.... we don't hog the processor if (!operation.CanContinue()) { Thread.Yield(); return; } using (var transactionContext = new DefaultTransactionContext()) { transactionContext.Items["CancellationToken"] = _cancellationTokenSource.Token; transactionContext.Items["OwningBus"] = _owningBus; AmbientTransactionContext.Current = transactionContext; try { var result = await TryReceiveTransportMessage(transactionContext, _cancellationTokenSource.Token); if (result.Exception != null) { if (result.Exception is TaskCanceledException || result.Exception is OperationCanceledException) { // this is normal - we're being shut down so we just return quickly transactionContext.Dispose(); return; } _log.Warn("An error occurred when attempting to receive transport message: {0}", result.Exception); // error: finish the tx and wait.... transactionContext.Dispose(); await _backoffStrategy.WaitError(); return; } var message = result.TransportMessage; if (message == null) { // no message: finish the tx and wait.... await transactionContext.Complete(); transactionContext.Dispose(); await _backoffStrategy.Wait(); return; } // we got a message, so we reset the backoff strategy _backoffStrategy.Reset(); var context = new IncomingStepContext(message, transactionContext); var stagedReceiveSteps = _pipeline.ReceivePipeline(); await _pipelineInvoker.Invoke(context, stagedReceiveSteps); try { await transactionContext.Complete(); } catch (Exception exception) { _log.Error(exception, "An error occurred when attempting to complete the transaction context"); } } catch (Exception exception) { // we should not end up here unless something is off.... _log.Error(exception, "Unhandled exception in thread worker - the pipeline didn't handle its own errors (this is bad)"); Thread.Sleep(100); } finally { AmbientTransactionContext.Current = null; } } } }
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); }