예제 #1
0
        public async Task Purge(TableBasedQueue queue, CancellationToken cancellationToken)
        {
            if (!enable)
            {
                Logger.DebugFormat("Purging expired messages on startup is not enabled for {0}.", queue);
                return;
            }

            Logger.DebugFormat("Starting a new expired message purge task for table {0}.", queue);
            var totalPurgedRowsCount = 0;

            try
            {
                using (var connection = await openConnection(queue).ConfigureAwait(false))
                {
                    var continuePurging = true;

                    while (continuePurging && !cancellationToken.IsCancellationRequested)
                    {
                        var purgedRowsCount = await queue.PurgeBatchOfExpiredMessages(connection, purgeBatchSize).ConfigureAwait(false);

                        totalPurgedRowsCount += purgedRowsCount;
                        continuePurging       = purgedRowsCount == purgeBatchSize;
                    }
                }

                Logger.DebugFormat("{0} expired messages were successfully purged from table {1}", totalPurgedRowsCount, queue);
            }
            catch
            {
                Logger.WarnFormat("Purging expired messages from table {0} failed after purging {1} messages.", queue, totalPurgedRowsCount);
                throw;
            }
        }
예제 #2
0
 public virtual async Task <int> Purge(TableBasedQueue queue)
 {
     using (var connection = await connectionFactory.OpenNewConnection().ConfigureAwait(false))
     {
         return(await queue.Purge(connection).ConfigureAwait(false));
     }
 }
예제 #3
0
        public void Init(TableBasedQueue inputQueue, TableBasedQueue errorQueue, Func <MessageContext, Task> onMessage, Func <ErrorContext, Task <ErrorHandleResult> > onError, CriticalError criticalError)
        {
            InputQueue = inputQueue;
            ErrorQueue = errorQueue;

            this.onMessage     = onMessage;
            this.onError       = onError;
            this.criticalError = criticalError;
        }
        async Task VerifyHeadersColumnType(TableBasedQueue queue)
        {
            try
            {
                using (var connection = await openConnection(queue).ConfigureAwait(false))
                {
                    var columnType = await queue.CheckHeadersColumnType(connection).ConfigureAwait(false);

                    if (string.Equals(columnType, "varchar", StringComparison.OrdinalIgnoreCase))
                    {
                        Logger.Warn($"Table {queue.Name} stores headers in a non Unicode-compatible column (varchar).{Environment.NewLine}This may lead to data loss when sending non-ASCII characters in headers. SQL Server transport 3.1 and newer can take advantage of the nvarchar column type for headers. Please change the column type in the database.");
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.WarnFormat("Checking indexes on table {0} failed. Exception: {1}", queue, ex);
            }
        }
        async Task VerifyExpiredIndex(TableBasedQueue queue)
        {
            try
            {
                using (var connection = await openConnection(queue).ConfigureAwait(false))
                {
                    var indexExists = await queue.CheckExpiresIndexPresence(connection).ConfigureAwait(false);

                    if (!indexExists)
                    {
                        Logger.Warn($@"Table {queue.Name} does not contain index 'Index_Expires'.{Environment.NewLine}Adding this index will speed up the process of purging expired messages from the queue. Please consult the documentation for further information.");
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.WarnFormat("Checking indexes on table {0} failed. Exception: {1}", queue, ex);
            }
        }
예제 #6
0
        public async Task <int> Peek(TableBasedQueue inputQueue, RepeatedFailuresOverTimeCircuitBreaker circuitBreaker, CancellationToken cancellationToken)
        {
            var messageCount = 0;

            try
            {
                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, cancellationToken).ConfigureAwait(false);

                        circuitBreaker.Success();

                        if (messageCount == 0)
                        {
                            Logger.Debug($"Input queue empty. Next peek operation will be delayed for {settings.Delay}.");

                            await Task.Delay(settings.Delay, cancellationToken).ConfigureAwait(false);
                        }

                        scope.Complete();
                    }
            }
            catch (OperationCanceledException)
            {
                //Graceful shutdown
            }
            catch (SqlException e) when(cancellationToken.IsCancellationRequested)
            {
                Logger.Debug("Exception thown while performing cancellation", e);
            }
            catch (Exception ex)
            {
                Logger.Warn("Sql peek operation failed", ex);
                await circuitBreaker.Failure(ex).ConfigureAwait(false);
            }

            return(messageCount);
        }
 public async Task PerformInspection(TableBasedQueue queue)
 {
     await VerifyExpiredIndex(queue).ConfigureAwait(false);
     await VerifyHeadersColumnType(queue).ConfigureAwait(false);
 }