public IDisposable Enter(DistributedMutexContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (_featureToggler.IsDisabled <DbDistributedMutex>()) { return(null); } return(new EnterLock(_db, _configuration, context, _queryLockInterval, _shutdown.Token)); }
public IDisposable Enter(DistributedMutexContext context) { if (_locks.ContainsKey(context.Name)) { throw new IsLockedException(); } if (_locks.TryAdd(context.Name, context)) { return(new DisposableAction(() => { DistributedMutexContext dummy; _locks.TryRemove(context.Name, out dummy); })); } throw new InvalidOperationException($"Unable to add lock for '{context.Name}."); }
public EnterLock(IDbFactory db, IIntegrationDatabaseConfiguration configuration, DistributedMutexContext context, TimeSpan queryLockInterval, CancellationToken cancellationToken) { _db = db; _configuration = configuration; _newLock = new DbDistributedMutexLock(context.Name) { MachineName = Environment.MachineName, Description = context.Description.MaxLength(255) }; using (IDbSession session = db.OpenSession()) { TimeSpan waitTime = context.WaitTime; int maxRetries = Math.Max((int)Math.Ceiling(waitTime.TotalMilliseconds / queryLockInterval.TotalMilliseconds), 1); int attempts = 0; DbDistributedMutexLock currentLock; while (true) { if (TryEnterLock(session, out currentLock)) { _onCancel = cancellationToken.Register(ReleaseLock); return; } if (currentLock == null) { throw new InvalidOperationException($"Cannot obtain lock for '{_newLock.Name}', but current lock is null."); } if (++attempts >= maxRetries) { break; } context.OnWaiting($"{currentLock}. Waiting for {queryLockInterval} (attemt {attempts} of {maxRetries})."); cancellationToken.WaitHandle.WaitOne(queryLockInterval); } throw new DistributedMutexTimeoutException($"Unable to acquire lock '{_newLock.Name}' within wait time ({waitTime}) using {attempts} attempts with a query interval of {queryLockInterval}. {currentLock}"); } }
public ConcurrentTaskExecutionResult Handle(ITask task, Arguments arguments, TaskLog log) { if (task == null) { throw new ArgumentNullException(nameof(task)); } if (arguments == null) { throw new ArgumentNullException(nameof(arguments)); } if (log == null) { throw new ArgumentNullException(nameof(log)); } Type taskType = task.GetType(); var preventConcurrent = taskType.GetCustomAttribute <PreventConcurrentTaskExecutionAttribute>(); if (preventConcurrent == null) { var allowConcurrentTaskExecutionAttribute = taskType.GetCustomAttribute <AllowConcurrentTaskExecutionAttribute>(); if (allowConcurrentTaskExecutionAttribute != null) { return(ConcurrentTaskExecutionResult.Continue()); } if (!_preventConcurrentTaskExecutionOnAllTasks) { return(ConcurrentTaskExecutionResult.Continue()); } } else { if (IsDisabled(task, arguments, preventConcurrent)) { return(ConcurrentTaskExecutionResult.Continue()); } } string lockName = GetLockName(task, arguments, preventConcurrent); string lockDescription = GetLockDescription(task, log, arguments, preventConcurrent); IPreventConcurrentTaskExecutionExceptionHandler exceptionHandler = GetExceptionHandler(task, preventConcurrent); try { DistributedMutexConfiguration configuration = preventConcurrent?.Configuration ?? _defaultConfiguration; var context = new DistributedMutexContext(lockName, configuration, log.LogMessage, lockDescription); IDisposable lockAcquired = _distributedMutex.Enter(context); return(ConcurrentTaskExecutionResult.Continue(lockAcquired)); } catch (Exception ex) { if (exceptionHandler != null) { ex = exceptionHandler.OnException(task, log, arguments, ex); if (ex == null) { return(ConcurrentTaskExecutionResult.Stop()); } } throw new TaskExecutionLockNotAcquiredException($"Unable to acquire lock '{lockName}'.", ex); } }