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 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); }