internal FluentNHibernateDistributedLock Acquire() { var finish = DateTime.UtcNow.Add(_timeout); while (!_cancellationToken.IsCancellationRequested && finish > DateTime.UtcNow) { if (SqlUtil.WrapForTransaction(() => SqlUtil.WrapForDeadlock(_cancellationToken, () => { _cancellationToken.WaitHandle.WaitOne(new TimeSpan(0, 0, 1)); var done = TryLock(() => { using (var session = _storage.GetStatelessSession()) { using (var transaction = session.BeginTransaction(IsolationLevel.Serializable)) { var count = session.Query <_DistributedLock>() .Count(i => i.Resource == _resource); if (count == 0) { var distributedLock = new _DistributedLock { CreatedAt = session.Storage.UtcNow, Resource = _resource, ExpireAtAsLong = session.Storage.UtcNow.Add(_timeout).ToEpochDate() }; session.Insert(distributedLock); _lockId = distributedLock.Id; transaction.Commit(); if (Logger.IsDebugEnabled()) { Logger.DebugFormat("Created distributed lock for {0}", JsonConvert.SerializeObject(distributedLock)); } return(true); } } return(false); } }, () => false); return(done); }, _options))) { Logger.DebugFormat("Granted distributed lock for {0}", _resource); return(this); } _cancellationToken.WaitHandle.WaitOne(_options.DistributedLockPollInterval); } return(null); }
internal void Release() { SqlUtil.WrapForTransaction(() => { SqlUtil.WrapForDeadlock(() => { lock (Mutex) { using (var session = _storage.GetSession()) { session.CreateQuery(SqlUtil.DeleteDistributedLockSql) .SetParameter(SqlUtil.IdParameterName, _resource) .ExecuteUpdate(); session.Flush(); Logger.DebugFormat("Released distributed lock for {0}", _resource); } } }, _options); }); }
internal void Release() { SqlUtil.WrapForTransaction(() => { SqlUtil.WrapForDeadlock(_cancellationToken, () => { lock (Mutex) { if (_lockId.HasValue) { using (var session = _storage.GetStatelessSession()) { session.Query <_DistributedLock>().Where(i => i.Id == _lockId).Delete(); Logger.DebugFormat("Released distributed lock for {0}", _resource); _lockId = null; } } } }, _options); }); }
private bool CreateLockRow() { return(SqlUtil.WrapForDeadlock(() => { lock (Mutex) { using (var session = _storage.GetSession()) { using (var transaction = session.BeginTransaction(IsolationLevel.Serializable)) { var lockResourceParams = new LockResourceParams(session, _resource, _timeout); var query = session.CreateQuery(SqlUtil.GetCreateDistributedLockStatement()) .SetParameter(SqlUtil.ResourceParameterName, lockResourceParams.Resource) .SetParameter(SqlUtil.ExpireAtAsLongParameterName, lockResourceParams.ExpireAtAsLong) .SetParameter(SqlUtil.CreatedAtParameterName, lockResourceParams.CreatedAt) .SetParameter(SqlUtil.UtcNowAsLongParameterName, lockResourceParams.CreatedAtAsLong); var count = query.ExecuteUpdate(); if (count == 1) { transaction.Commit(); if (Logger.IsDebugEnabled()) { Logger.DebugFormat("Created distributed lock for {0}", JsonConvert.SerializeObject(lockResourceParams)); } return true; } } } return false; } }, _options)); }
internal void Initialize() { var started = Stopwatch.StartNew(); do { if (SqlUtil.WrapForTransaction(() => SqlUtil.WrapForDeadlock(_cancellationToken, () => { var done = TryLock(() => { var result = false; _storage.UseStatelessSessionInTransaction(session => { var distributedLock = session.Query <_DistributedLock>() .FirstOrDefault(i => i.Resource == _resource); var utcNow = session.Storage.UtcNow; var expireAtAsLong = utcNow.Add(_timeout).ToEpochDate(); if (distributedLock == null) { distributedLock = new _DistributedLock { CreatedAt = utcNow, Resource = _resource, ExpireAtAsLong = expireAtAsLong }; session.Insert(distributedLock); _lockId = distributedLock.Id; result = true; if (Logger.IsDebugEnabled()) { Logger.Debug($"Inserted row for distributed lock '{_resource}'"); } } else if (distributedLock.ExpireAtAsLong < utcNow.ToEpochDate()) { distributedLock.CreatedAt = utcNow; distributedLock.ExpireAtAsLong = expireAtAsLong; session.Update(distributedLock); if (Logger.IsDebugEnabled()) { Logger.Debug($"Re-used row for distributed lock '{_resource}'"); } _lockId = distributedLock.Id; result = true; } }); return(result); }, () => false); return(done); }, _options))) { if (Logger.IsDebugEnabled()) { Logger.DebugFormat("Granted distributed lock '{0}'", _resource); } return; } if (started.Elapsed > _timeout) { break; } if (Logger.IsDebugEnabled()) { Logger.Debug( $"Will poll for distributed lock '{_resource}' in {_options.DistributedLockPollInterval}."); } _cancellationToken.Wait(_options.DistributedLockPollInterval); } while (true); //dont change this. Hangfire looks for resource name in exception properties throw new DistributedLockTimeoutException(_resource); }