public async Task Init(Func <MessageContext, Task> onMessage, Func <ErrorContext, Task <ErrorHandleResult> > onError, CriticalError criticalError, PushSettings settings) { receiveStrategy = receiveStrategyFactory(settings.RequiredTransactionMode); peekCircuitBreaker = new RepeatedFailuresOverTimeCircuitBreaker("SqlPeek", waitTimeCircuitBreaker, ex => criticalError.Raise("Failed to peek " + settings.InputQueue, ex)); receiveCircuitBreaker = new RepeatedFailuresOverTimeCircuitBreaker("ReceiveText", waitTimeCircuitBreaker, ex => criticalError.Raise("Failed to receive from " + settings.InputQueue, ex)); inputQueue = queueFactory(settings.InputQueue); errorQueue = queueFactory(settings.ErrorQueue); receiveStrategy.Init(inputQueue, errorQueue, onMessage, onError, criticalError); if (settings.PurgeOnStartup) { try { var purgedRowsCount = await queuePurger.Purge(inputQueue).ConfigureAwait(false); Logger.InfoFormat("{0:N0} messages purged from queue {1}", purgedRowsCount, settings.InputQueue); } catch (Exception ex) { Logger.Warn("Failed to purge input queue on startup.", ex); } } await PurgeExpiredMessages().ConfigureAwait(false); await schemaInspector.PerformInspection(inputQueue).ConfigureAwait(false); }
public async Task Initialize(PushRuntimeSettings limitations, OnMessage onMessage, OnError onError, CancellationToken cancellationToken = default) { this.limitations = limitations; messageReceivingCancellationTokenSource = new CancellationTokenSource(); messageProcessingCancellationTokenSource = new CancellationTokenSource(); processStrategy = processStrategyFactory(transport.TransportTransactionMode); messageReceivingCircuitBreaker = new RepeatedFailuresOverTimeCircuitBreaker("message receiving", waitTimeCircuitBreaker, ex => hostSettings.CriticalErrorAction("Failed to peek " + receiveSettings.ReceiveAddress, ex, messageProcessingCancellationTokenSource.Token)); messageProcessingCircuitBreaker = new RepeatedFailuresOverTimeCircuitBreaker("message processing", waitTimeCircuitBreaker, ex => hostSettings.CriticalErrorAction("Failed to receive from " + receiveSettings.ReceiveAddress, ex, messageProcessingCancellationTokenSource.Token)); inputQueue = queueFactory(receiveSettings.ReceiveAddress); errorQueue = queueFactory(receiveSettings.ErrorQueue); processStrategy.Init(inputQueue, errorQueue, onMessage, onError, hostSettings.CriticalErrorAction); if (transport.ExpiredMessagesPurger.PurgeOnStartup) { try { var purgedRowsCount = await queuePurger.Purge(inputQueue, cancellationToken).ConfigureAwait(false); Logger.InfoFormat("{0:N0} messages purged from queue {1}", purgedRowsCount, receiveSettings.ReceiveAddress); } catch (Exception ex) when(!ex.IsCausedBy(cancellationToken)) { Logger.Warn("Failed to purge input queue on startup.", ex); } } await PurgeExpiredMessages(cancellationToken).ConfigureAwait(false); await schemaInspector.PerformInspection(inputQueue, cancellationToken).ConfigureAwait(false); }
public void Start(CancellationToken cancellationToken = default) { moveDelayedMessagesCancellationTokenSource = new CancellationTokenSource(); dueDelayedMessageProcessorCircuitBreaker = new RepeatedFailuresOverTimeCircuitBreaker("due delayed message processing", waitTimeCircuitBreaker, ex => hostSettings.CriticalErrorAction("Failed to move matured delayed messages to input queue", ex, moveDelayedMessagesCancellationTokenSource.Token)); // Task.Run() so the call returns immediately instead of waiting for the first await or return down the call stack moveDelayedMessagesTask = Task.Run(() => MoveMaturedDelayedMessagesAndSwallowExceptions(moveDelayedMessagesCancellationTokenSource.Token), CancellationToken.None); }
public async Task <int> Peek(TableBasedQueue inputQueue, RepeatedFailuresOverTimeCircuitBreaker circuitBreaker, CancellationToken cancellationToken) { var messageCount = 0; try { #if NETFRAMEWORK using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }, TransactionScopeAsyncFlowOption.Enabled)) using (var connection = await connectionFactory.OpenNewConnection().ConfigureAwait(false)) { messageCount = await inputQueue.TryPeek(connection, null, cancellationToken).ConfigureAwait(false); scope.Complete(); } #else using (var scope = new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled)) using (var connection = await connectionFactory.OpenNewConnection().ConfigureAwait(false)) using (var tx = connection.BeginTransaction()) { messageCount = await inputQueue.TryPeek(connection, tx, cancellationToken).ConfigureAwait(false); tx.Commit(); scope.Complete(); } #endif circuitBreaker.Success(); } catch (OperationCanceledException) { //Graceful shutdown } catch (SqlException e) when(cancellationToken.IsCancellationRequested) { Logger.Debug("Exception thrown while performing cancellation", e); } catch (Exception ex) { Logger.Warn("Sql peek operation failed", ex); await circuitBreaker.Failure(ex).ConfigureAwait(false); } if (messageCount == 0) { if (Logger.IsDebugEnabled) { Logger.Debug($"Input queue empty. Next peek operation will be delayed for {settings.Delay}."); } // This doesn't require a try/catch (OperationCanceledException) because the upper layers handle the shutdown case gracefully await Task.Delay(settings.Delay, cancellationToken).ConfigureAwait(false); } return(messageCount); }
public async Task <int> Peek(TableBasedQueue inputQueue, RepeatedFailuresOverTimeCircuitBreaker circuitBreaker, CancellationToken cancellationToken = default) { var messageCount = 0; try { #if NETFRAMEWORK using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }, TransactionScopeAsyncFlowOption.Enabled)) using (var connection = await connectionFactory.OpenNewConnection(cancellationToken).ConfigureAwait(false)) { messageCount = await inputQueue.TryPeek(connection, null, cancellationToken : cancellationToken).ConfigureAwait(false); scope.Complete(); } #else using (var scope = new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled)) using (var connection = await connectionFactory.OpenNewConnection(cancellationToken).ConfigureAwait(false)) using (var tx = connection.BeginTransaction()) { messageCount = await inputQueue.TryPeek(connection, tx, cancellationToken : cancellationToken).ConfigureAwait(false); tx.Commit(); scope.Complete(); } #endif circuitBreaker.Success(); } catch (Exception ex) when(!ex.IsCausedBy(cancellationToken)) { Logger.Warn("Sql peek operation failed", ex); await circuitBreaker.Failure(ex, cancellationToken).ConfigureAwait(false); } if (messageCount == 0) { if (Logger.IsDebugEnabled) { Logger.Debug($"Input queue empty. Next peek operation will be delayed for {settings.Delay}."); } await Task.Delay(settings.Delay, cancellationToken).ConfigureAwait(false); } return(messageCount); }