Example #1
0
        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}.");
            }
Example #3
0
            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}");
                }
            }
Example #4
0
        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);
            }
        }