public virtual async Task <int> Purge(TableBasedQueue queue, CancellationToken cancellationToken = default)
 {
     using (var connection = await connectionFactory.OpenNewConnection(cancellationToken).ConfigureAwait(false))
     {
         return(await queue.Purge(connection, cancellationToken).ConfigureAwait(false));
     }
 }
Esempio n. 2
0
        public async Task Purge(TableBasedQueue queue, CancellationToken cancellationToken)
        {
            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;
            }
        }
 public virtual async Task <int> Purge(TableBasedQueue queue)
 {
     using (var connection = await connectionFactory.OpenNewConnection().ConfigureAwait(false))
     {
         return(await queue.Purge(connection).ConfigureAwait(false));
     }
 }
Esempio n. 4
0
 Task VerifyNonClusteredRowVersionIndex(TableBasedQueue queue)
 {
     return(VerifyIndex(
                queue,
                (q, c) => q.CheckNonClusteredRowVersionIndexPresence(c),
                $"Table {queue.Name} does not contain non-clustered index 'Index_RowVersion'.{Environment.NewLine}Migrating to this non-clustered index improves performance for send and receive operations."));
 }
Esempio n. 5
0
 Task VerifyExpiredIndex(TableBasedQueue queue)
 {
     return(VerifyIndex(
                queue,
                (q, c) => q.CheckExpiresIndexPresence(c),
                $"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."
                ));
 }
        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;
        }
        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);
        }
Esempio n. 8
0
        public void Init(TableBasedQueue inputQueue, TableBasedQueue errorQueue, OnMessage onMessage, OnError onError, Action <string, Exception, CancellationToken> criticalError)
        {
            this.inputQueue = inputQueue;
            this.errorQueue = errorQueue;

            this.onMessage     = onMessage;
            this.onError       = onError;
            this.criticalError = criticalError;
        }
Esempio n. 9
0
        public async Task PerformInspection(TableBasedQueue queue, CancellationToken cancellationToken = default)
        {
            if (validateExpiredIndex)
            {
                await VerifyExpiredIndex(queue, cancellationToken).ConfigureAwait(false);
            }

            await VerifyNonClusteredRowVersionIndex(queue, cancellationToken).ConfigureAwait(false);
            await VerifyHeadersColumnType(queue, cancellationToken).ConfigureAwait(false);
        }
Esempio n. 10
0
        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);
        }
Esempio n. 11
0
        async Task VerifyHeadersColumnType(TableBasedQueue queue, CancellationToken cancellationToken)
        {
            try
            {
                using (var connection = await openConnection(queue, cancellationToken).ConfigureAwait(false))
                {
                    var columnType = await queue.CheckHeadersColumnType(connection, cancellationToken).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) when(!ex.IsCausedBy(cancellationToken))
            {
                Logger.WarnFormat("Checking indexes on table {0} failed. Exception: {1}", queue, ex);
            }
        }
Esempio n. 12
0
        async Task VerifyIndex(TableBasedQueue queue, Func <TableBasedQueue, SqlConnection, CancellationToken, Task <bool> > check, string noIndexMessage, CancellationToken cancellationToken)
        {
            try
            {
                using (var connection = await openConnection(queue, cancellationToken).ConfigureAwait(false))
                {
                    var indexExists = await check(queue, connection, cancellationToken).ConfigureAwait(false);

                    if (!indexExists)
                    {
                        Logger.Warn(noIndexMessage);
                    }
                }
            }
            catch (Exception ex) when(!ex.IsCausedBy(cancellationToken))
            {
                Logger.WarnFormat("Checking indexes on table {0} failed. Exception: {1}", queue, ex);
            }
        }
 public Task Purge(TableBasedQueue queue, CancellationToken cancellationToken)
 {
     return(Task.CompletedTask);
 }