private IDisposable AcquireLock(string resource, TimeSpan timeout)
        {
            if (_dedicatedConnection == null)
            {
                _dedicatedConnection = _storage.CreateAndOpenConnection();
            }

            var lockId = Guid.NewGuid();

            if (!_lockedResources.ContainsKey(resource))
            {
                try
                {
                    SqlServerDistributedLock.Acquire(_dedicatedConnection, resource, timeout);
                }
                catch (Exception)
                {
                    ReleaseLock(resource, lockId, true);
                    throw;
                }

                _lockedResources.Add(resource, new HashSet <Guid>());
            }

            _lockedResources[resource].Add(lockId);
            return(new DisposableLock(this, resource, lockId));
        }
Example #2
0
        private void UseConnectionDistributedLock(SqlServerStorage storage, Action <DbConnection> action)
        {
            try
            {
                storage.UseConnection(null, connection =>
                {
                    SqlServerDistributedLock.Acquire(connection, DistributedLockKey, DefaultLockTimeout);

                    try
                    {
                        action(connection);
                    }
                    finally
                    {
                        SqlServerDistributedLock.Release(connection, DistributedLockKey);
                    }
                });
            }
            catch (DistributedLockTimeoutException e) when(e.Resource == DistributedLockKey)
            {
                // DistributedLockTimeoutException here doesn't mean that outdated records weren't removed.
                // It just means another Hangfire server did this work.
                _logger.Log(
                    LogLevel.Debug,
                    () => $@"An exception was thrown during acquiring distributed lock on the {DistributedLockKey} resource within {DefaultLockTimeout.TotalSeconds} seconds. Outdated records were not removed.
It will be retried in {_checkInterval.TotalSeconds} seconds.",
                    e);
            }
        }
Example #3
0
        public void Execute(CancellationToken cancellationToken)
        {
            foreach (var table in ProcessedTables)
            {
                Logger.Debug($"Removing outdated records from the '{table}' table...");

                _storage.UseConnection(connection =>
                {
                    SqlServerDistributedLock.Acquire(connection, DistributedLockKey, DefaultLockTimeout);

                    try
                    {
                        ExecuteNonQuery(
                            connection,
                            GetQuery(_storage.SchemaName, table),
                            cancellationToken,
                            new SqlParameter("@count", NumberOfRecordsInSinglePass),
                            new SqlParameter("@now", DateTime.UtcNow));
                    }
                    finally
                    {
                        SqlServerDistributedLock.Release(connection, DistributedLockKey);
                    }
                });

                Logger.Trace($"Outdated records removed from the '{table}' table.");
            }

            cancellationToken.WaitHandle.WaitOne(_checkInterval);
        }
Example #4
0
        public void Execute(CancellationToken cancellationToken)
        {
            foreach (var table in ProcessedTables)
            {
                Logger.DebugFormat("Removing outdated records from table '{0}'...", table);

                int removedCount = 0;

                do
                {
                    _storage.UseConnection(connection =>
                    {
                        SqlServerDistributedLock.Acquire(connection, DistributedLockKey, DefaultLockTimeout);

                        try
                        {
                            removedCount = connection.Execute(
                                String.Format(@"
set transaction isolation level read committed;
delete top (@count) from [{0}].[{1}] with (readpast) where ExpireAt < @now;", _storage.GetSchemaName(), table),
                                new { now = DateTime.UtcNow, count = NumberOfRecordsInSinglePass });
                        }
                        finally
                        {
                            SqlServerDistributedLock.Release(connection, DistributedLockKey);
                        }
                    });

                    if (removedCount > 0)
                    {
                        Logger.Trace(String.Format("Removed {0} outdated record(s) from '{1}' table.", removedCount,
                                                   table));

                        cancellationToken.WaitHandle.WaitOne(DelayBetweenPasses);
                        cancellationToken.ThrowIfCancellationRequested();
                    }
                } while (removedCount != 0);
            }

            cancellationToken.WaitHandle.WaitOne(_checkInterval);
        }
Example #5
0
        public void Execute(CancellationToken cancellationToken)
        {
            foreach (var table in ProcessedTables)
            {
                Logger.Debug($"Removing outdated records from table '{table}'...");

                int removedCount = 0;

                do
                {
                    _storage.UseConnection(connection =>
                    {
                        SqlServerDistributedLock.Acquire(connection, DistributedLockKey, DefaultLockTimeout);

                        try
                        {
                            removedCount = connection.Execute(
                                $@"set transaction isolation level read committed;
delete top (@count) from [{_storage.SchemaName}].[{table}] with (readpast) where ExpireAt < @now;",
                                new { now = DateTime.UtcNow, count = NumberOfRecordsInSinglePass });
                        }
                        finally
                        {
                            SqlServerDistributedLock.Release(connection, DistributedLockKey);
                        }
                    });

                    if (removedCount > 0)
                    {
                        Logger.Trace($"Removed {removedCount} outdated record(s) from '{table}' table.");

                        cancellationToken.WaitHandle.WaitOne(DelayBetweenPasses);
                        cancellationToken.ThrowIfCancellationRequested();
                    }
                    // ReSharper disable once LoopVariableIsNeverChangedInsideLoop
                } while (removedCount != 0);
            }

            cancellationToken.WaitHandle.WaitOne(_checkInterval);
        }
Example #6
0
 private void ReleaseLock(string resource, Guid lockId, bool onDisposing)
 {
     try
     {
         if (_lockedResources.ContainsKey(resource))
         {
             if (_lockedResources[resource].Contains(lockId))
             {
                 if (_lockedResources[resource].Remove(lockId) &&
                     _lockedResources[resource].Count == 0 &&
                     _lockedResources.Remove(resource) &&
                     _dedicatedConnection.State == ConnectionState.Open)
                 {
                     // Session-scoped application locks are held only when connection
                     // is open. When connection is closed or broken, for example, when
                     // there was an error, application lock is already released by SQL
                     // Server itself, and we shouldn't do anything.
                     SqlServerDistributedLock.Release(_dedicatedConnection, resource);
                 }
             }
         }
     }
     catch (Exception)
     {
         if (!onDisposing)
         {
             throw;
         }
     }
     finally
     {
         if (_lockedResources.Count == 0)
         {
             _storage.ReleaseConnection(_dedicatedConnection);
             _dedicatedConnection = null;
         }
     }
 }