public IDistributedLock AcquireLock(string name, TimeSpan?maxValidFor, TimeSpan?timeout) { try { DistributedLock result = AcquireLockInternal(name, maxValidFor, timeout, throwOnTimeout: true); Logger.Debug("Successfully acquired lock '{0}'.", name); return(result); } catch (Exception ex) { Logger.Error(ex, "Error while trying to acquire lock '{0}'.", name); throw; } }
private DistributedLock AcquireLockInternal(string name, TimeSpan?maxValidFor, TimeSpan?timeout, bool throwOnTimeout) { var internalName = GetInternalLockName(name); var monitorTimeout = timeout.HasValue ? timeout.Value : TimeSpan.FromMilliseconds(-1); // -1 ms is .NET magic number for "infinite". var monitorObj = String.Intern(String.Format("{0}:{1}", _applicationEnvironment.GetEnvironmentIdentifier(), internalName)); if (!Monitor.TryEnter(monitorObj, monitorTimeout)) { Logger.Debug("Could not enter local monitor for lock '{0}' within the specified timeout ({1}).", internalName, timeout); if (throwOnTimeout) { throw new TimeoutException(String.Format("Failed to acquire lock '{0}' within the specified timeout ({1}).", internalName, timeout)); } return(null); } Logger.Debug("Successfully entered local monitor for lock '{0}'.", internalName); try { DistributedLock dLock = null; // If there's already a distributed lock object in our dictionary, that means // this acquisition is a reentrance. Use the existing lock object from the // dictionary but increment its count. if (_locks.TryGetValue(monitorObj, out dLock)) { Logger.Debug("Current thread is re-entering lock '{0}'; incrementing count.", internalName); dLock.Increment(); } else { // No distributed lock object existed in our dictionary. Try to take ownership // of database record until timeout expires, and if successful create a distributed // lock object and add it to our dictionary. var success = RepeatUntilTimeout(timeout, _defaultRepeatInterval, () => { if (EnsureDistributedLockRecord(internalName, maxValidFor)) { Logger.Debug("Record for lock '{0}' already owned by current machine or was successfully created; creating lock object.", internalName); dLock = new DistributedLock(name, internalName, releaseLockAction: () => { Monitor.Exit(monitorObj); DeleteDistributedLockRecord(internalName); }); _locks.Add(monitorObj, dLock); return(true); } return(false); }); if (!success) { Logger.Debug("Record for lock '{0}' could not be created for current machine within the specified timeout ({1}).", internalName, timeout); if (throwOnTimeout) { throw new TimeoutException(String.Format("Failed to acquire lock '{0}' within the specified timeout ({1}).", internalName, timeout)); } return(null); } } return(dLock); } catch (Exception ex) { Monitor.Exit(monitorObj); Logger.Error(ex, "An error occurred while trying to acquire lock '{0}'.", internalName); throw; } }