/// <summary>
        /// Constructor
        /// </summary>
        /// <param name="connectionProvider">A <see cref="IDbConnection"/> to obtain a database connection</param>
        /// <param name="lockTableName">Name of the queue this transport is servicing</param>
        /// <param name="rebusLoggerFactory">A <seealso cref="IRebusLoggerFactory"/> for building loggers</param>
        /// <param name="asyncTaskFactory">A <seealso cref="IAsyncTaskFactory"/> for creating periodic tasks</param>
        /// <param name="rebusTime">A <seealso cref="IRebusTime"/> to provide the current time</param>
        /// <param name="options">Additional options</param>
        public MySqlExclusiveAccessLock(
            IDbConnectionProvider connectionProvider,
            string lockTableName,
            IRebusLoggerFactory rebusLoggerFactory,
            IAsyncTaskFactory asyncTaskFactory,
            IRebusTime rebusTime,
            MySqlExclusiveAccessLockOptions options)
        {
            if (rebusLoggerFactory == null)
            {
                throw new ArgumentNullException(nameof(rebusLoggerFactory));
            }
            if (asyncTaskFactory == null)
            {
                throw new ArgumentNullException(nameof(asyncTaskFactory));
            }

            _rebusTime          = rebusTime ?? throw new ArgumentNullException(nameof(rebusTime));
            _connectionProvider = connectionProvider ?? throw new ArgumentNullException(nameof(connectionProvider));
            _lockTableName      = lockTableName != null?TableName.Parse(lockTableName) : null;

            _log = rebusLoggerFactory.GetLogger <MySqlExclusiveAccessLock>();
            _lockExpirationTimeout = options.LockExpirationTimeout ?? DefaultLockExpirationTimeout;

            var cleanupInterval = options.ExpiredLocksCleanupInterval ?? DefaultExpiredLocksCleanupInterval;
            var intervalSeconds = (int)cleanupInterval.TotalSeconds;

            _expiredLocksCleanupTask = asyncTaskFactory.Create("ExpiredLocksCleanup", PerformExpiredLocksCleanupCycle, intervalSeconds: intervalSeconds);
            _autoDeleteTable         = options.AutoDeleteTable;
        }
        public async Task TestMySqlSagaLocks()
        {
            var loggerFactory = new ListLoggerFactory(outputToConsole: true);
            var network       = new InMemNetwork();

            var handlerActivator = Using(new BuiltinHandlerActivator());

            handlerActivator.Handle <ProcessThisThingRequest>((bus, request) => bus.Reply(new ProcessThisThingReply(request.Thing, request.SagaId)));

            Configure.With(handlerActivator)
            .Logging(l => l.None())
            .Transport(t => t.UseInMemoryTransport(network, "processor"))
            .Start();

            var sagaActivator = Using(new BuiltinHandlerActivator());

            sagaActivator.Register((bus, context) => new TypicalContendedSagaExample(bus));

            Configure.With(sagaActivator)
            .Logging(l => l.Use(loggerFactory))
            .Transport(t => t.UseInMemoryTransport(network, "lock-test"))
            .Sagas(s =>
            {
                s.StoreInMySql(MySqlTestHelper.ConnectionString, _dataTableName, _indexTableName);
                s.EnforceExclusiveAccess(c =>
                {
                    var options            = new MySqlExclusiveAccessLockOptions(MySqlTestHelper.ConnectionString);
                    var rebusLoggerFactory = c.Get <IRebusLoggerFactory>();
                    var connectionProvider = options.ConnectionProviderFactory(c);
                    var asyncTaskFactory   = c.Get <IAsyncTaskFactory>();
                    var rebusTime          = c.Get <IRebusTime>();
                    var locker             = new MySqlExclusiveAccessLock(connectionProvider, _lockTableName, rebusLoggerFactory, asyncTaskFactory, rebusTime, options);
                    if (options.EnsureTablesAreCreated)
                    {
                        locker.EnsureTableIsCreated();
                    }
                    return(locker);
                });
            })
            .Routing(t => t.TypeBased().Map <ProcessThisThingRequest>("processor"))
            .Options(o =>
            {
                o.SetMaxParallelism(100);
                o.SetNumberOfWorkers(10);
            })
            .Start();

            await sagaActivator.Bus.SendLocal(new ProcessTheseThings(Enumerable.Range(0, 10).Select(no => $"THING-{no}")));

            await Task.Delay(TimeSpan.FromSeconds(System.Diagnostics.Debugger.IsAttached ? 30 : 3));

            Assert.That(loggerFactory.Count(l => l.Level >= LogLevel.Warn), Is.EqualTo(0), "Didn't expect any logging with level WARNING or above");
        }