public Task StartReceive(CancellationToken cancellationToken = default) { maxConcurrency = limitations.MaxConcurrency; var prefetchCount = maxConcurrency * transportSettings.PrefetchMultiplier; if (transportSettings.PrefetchCount.HasValue) { prefetchCount = transportSettings.PrefetchCount.Value; } var receiveOptions = new ServiceBusReceiverOptions() { PrefetchCount = prefetchCount, ReceiveMode = transportSettings.TransportTransactionMode == TransportTransactionMode.None ? ServiceBusReceiveMode.ReceiveAndDelete : ServiceBusReceiveMode.PeekLock }; receiver = serviceBusClient.CreateReceiver(ReceiveAddress, receiveOptions); concurrencyLimiter = new SemaphoreSlim(maxConcurrency, maxConcurrency); messageReceivingCancellationTokenSource = new CancellationTokenSource(); messageProcessingCancellationTokenSource = new CancellationTokenSource(); circuitBreaker = new RepeatedFailuresOverTimeCircuitBreaker($"'{receiveSettings.ReceiveAddress}'", transportSettings.TimeToWaitBeforeTriggeringCircuitBreaker, ex => criticalErrorAction("Failed to receive message from Azure Service Bus.", ex, messageProcessingCancellationTokenSource.Token)); // no Task.Run() here because ReceiveMessagesAndSwallowExceptions immediately yields with an await messageReceivingTask = ReceiveMessagesAndSwallowExceptions(messageReceivingCancellationTokenSource.Token); return(Task.CompletedTask); }
public Task Init(Func <MessageContext, Task> pump, Func <ErrorContext, Task <ErrorHandleResult> > onError, CriticalError criticalError, PushSettings pushSettings) { topologyOperator = DetermineTopologyOperator(pushSettings.InputQueue); messagePump = pump; var name = $"MessagePump on the queue `{pushSettings.InputQueue}`"; circuitBreaker = new RepeatedFailuresOverTimeCircuitBreaker(name, timeToWaitBeforeTriggering, ex => criticalError.Raise("Failed to receive message from Azure Service Bus.", ex)); if (pushSettings.PurgeOnStartup) { throw new InvalidOperationException("Azure Service Bus transport doesn't support PurgeOnStartup behavior"); } inputQueue = pushSettings.InputQueue; topologyOperator.OnIncomingMessage(async(incoming, receiveContext) => { if (circuitBreaker == null || throttler == null) /* can be disposed by fody injected logic, in theory */ { return; } var tokenSource = new CancellationTokenSource(); receiveContext.CancellationToken = tokenSource.Token; circuitBreaker.Success(); var transportTransaction = new TransportTransaction(); transportTransaction.Set(receiveContext); await throttler.WaitAsync(receiveContext.CancellationToken).ConfigureAwait(false); try { await messagePump(new MessageContext(incoming.MessageId, incoming.Headers, incoming.Body, transportTransaction, tokenSource, new ContextBag())).ConfigureAwait(false); } finally { throttler.Release(); } }); topologyOperator.OnError(exception => circuitBreaker?.Failure(exception)); topologyOperator.OnProcessingFailure(onError); topologyOperator.SetCriticalError(criticalError); return(TaskEx.Completed); }
public Task Init(Func <MessageContext, Task> onMessage, Func <ErrorContext, Task <ErrorHandleResult> > onError, CriticalError criticalError, PushSettings settings) { if (settings.PurgeOnStartup) { throw new Exception("Azure Service Bus transport doesn't support PurgeOnStartup behavior"); } this.onMessage = onMessage; this.onError = onError; pushSettings = settings; circuitBreaker = new RepeatedFailuresOverTimeCircuitBreaker($"'{settings.InputQueue}'", timeToWaitBeforeTriggeringCircuitBreaker, criticalError); return(Task.CompletedTask); }