public async Task <bool> CheckIsStillLockedAsync(DistributedLockSettings settings)
        {
            Check.NotNull(settings, nameof(settings));

            if (settings is NullLockSettings)
            {
                return(await NullLockManager.CheckIsStillLockedAsync(settings).ConfigureAwait(false));
            }

            try
            {
                using var scope = _serviceScopeFactory.CreateScope();
                return(await CheckIsStillLockedAsync(
                           settings.ResourceName,
                           settings.UniqueId,
                           settings.HeartbeatTimeout,
                           scope.ServiceProvider)
                       .ConfigureAwait(false));
            }
            catch (Exception ex)
            {
                _logger.LogFailedToCheckLock(settings, ex);
                return(false);
            }
        }
예제 #2
0
        public async Task <DistributedLock> Acquire(DistributedLockSettings settings, CancellationToken cancellationToken = default)
        {
            if (settings == null)
            {
                throw new ArgumentNullException(nameof(settings));
            }

            _logger.LogInformation("Trying to acquire lock {lockName} ({lockUniqueId})...", settings.ResourceName, settings.UniqueId);

            var stopwatch = Stopwatch.StartNew();

            while (settings.AcquireTimeout == null || stopwatch.Elapsed < settings.AcquireTimeout)
            {
                if (await TryAcquireLock(settings))
                {
                    _logger.LogInformation("Acquired lock {lockName} ({lockUniqueId}).", settings.ResourceName, settings.UniqueId);
                    return(new DistributedLock(settings, this));
                }

                await Task.Delay(settings.AcquireRetryInterval, cancellationToken);

                if (cancellationToken.IsCancellationRequested)
                {
                    break;
                }
            }

            throw new TimeoutException($"Timeout waiting to get the required lock '{settings.ResourceName}'.");
        }
        public async Task ReleaseAsync(DistributedLockSettings settings)
        {
            Check.NotNull(settings, nameof(settings));

            if (settings is NullLockSettings)
            {
                await NullLockManager.ReleaseAsync(settings).ConfigureAwait(false);
            }

            var tryCount = 1;

            while (tryCount <= 3)
            {
                try
                {
                    using var scope = _serviceScopeFactory.CreateScope();
                    await ReleaseAsync(settings.ResourceName, settings.UniqueId, scope.ServiceProvider)
                    .ConfigureAwait(false);

                    _logger.LogLockReleased(settings);

                    break;
                }
                catch (Exception ex)
                {
                    _logger.LogFailedToReleaseLock(settings, ex);
                    tryCount++;
                }
            }
        }
        public async Task <bool> CheckIsStillLockedAsync(DistributedLockSettings settings)
        {
            Check.NotNull(settings, nameof(settings));

            if (settings is NullLockSettings)
            {
                return(await NullLockManager.CheckIsStillLockedAsync(settings).ConfigureAwait(false));
            }

            try
            {
                using var scope = _serviceScopeFactory.CreateScope();
                return(await CheckIsStillLockedAsync(
                           settings.ResourceName,
                           settings.UniqueId,
                           settings.HeartbeatTimeout,
                           scope.ServiceProvider)
                       .ConfigureAwait(false));
            }
            catch (Exception ex)
            {
                _logger.LogError(
                    CoreEventIds.FailedToCheckDistributedLock,
                    ex,
                    "Failed to check lock {lockName} ({lockUniqueId}). See inner exception for details.",
                    settings.ResourceName,
                    settings.UniqueId);

                return(false);
            }
        }
        public async Task <bool> SendHeartbeatAsync(DistributedLockSettings settings)
        {
            Check.NotNull(settings, nameof(settings));

            if (settings is NullLockSettings)
            {
                return(await NullLockManager.SendHeartbeatAsync(settings).ConfigureAwait(false));
            }

            try
            {
                using var scope = _serviceScopeFactory.CreateScope();
                return(await SendHeartbeatAsync(settings.ResourceName, settings.UniqueId, scope.ServiceProvider)
                       .ConfigureAwait(false));
            }
            catch (Exception ex)
            {
                _logger.LogDebug(
                    CoreEventIds.FailedToSendDistributedLockHeartbeat,
                    ex,
                    "Failed to send heartbeat for lock {lockName} ({lockUniqueId}). See inner exception for details.",
                    settings.ResourceName,
                    settings.UniqueId);

                return(false);
            }
        }
예제 #6
0
        public DistributedLock(DistributedLockSettings settings, IDistributedLockManager lockManager)
        {
            _settings    = settings ?? throw new ArgumentNullException(nameof(settings));
            _lockManager = lockManager ?? throw new ArgumentNullException(nameof(lockManager));

            Status = DistributedLockStatus.Acquired;

            Task.Run(SendHeartbeats);
        }
예제 #7
0
        protected DistributedBackgroundService(DistributedLockSettings distributedLockSettings, IDistributedLockManager distributedLockManager, ILogger <DistributedBackgroundService> logger)
        {
            _distributedLockSettings = distributedLockSettings ?? new DistributedLockSettings();
            _distributedLockManager  = distributedLockManager ?? throw new ArgumentNullException(nameof(distributedLockManager));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));

            if (string.IsNullOrEmpty(_distributedLockSettings.ResourceName))
            {
                _distributedLockSettings.ResourceName = GetType().FullName;
            }
        }
        /// <summary>
        ///     Initializes a new instance of the <see cref="DistributedBackgroundService" /> class.
        /// </summary>
        /// <param name="distributedLockSettings">
        ///     Customizes the lock mechanism settings.
        /// </param>
        /// <param name="distributedLockManager">
        ///     The <see cref="IDistributedLockManager" />.
        /// </param>
        /// <param name="logger">
        ///     The <see cref="ISilverbackLogger" />.
        /// </param>
        protected DistributedBackgroundService(
            DistributedLockSettings?distributedLockSettings,
            IDistributedLockManager distributedLockManager,
            ISilverbackLogger <DistributedBackgroundService> logger)
        {
            _distributedLockSettings = distributedLockSettings ?? new DistributedLockSettings();

            _distributedLockSettings.EnsureResourceNameIsSet(GetType().FullName);

            _distributedLockManager = Check.NotNull(distributedLockManager, nameof(distributedLockManager));
            _logger = Check.NotNull(logger, nameof(logger));
        }
예제 #9
0
        /// <summary>
        ///     Initializes a new instance of the <see cref="DistributedLock" /> class.
        /// </summary>
        /// <param name="settings">
        ///     Specifies all settings of the lock to be acquired.
        /// </param>
        /// <param name="lockManager">
        ///     The <see cref="IDistributedLockManager" /> that generated the lock and can be used to keep it alive
        ///     and finally release it.
        /// </param>
        public DistributedLock(DistributedLockSettings settings, IDistributedLockManager lockManager)
        {
            _settings    = Check.NotNull(settings, nameof(settings));
            _lockManager = Check.NotNull(lockManager, nameof(lockManager));

            Status = DistributedLockStatus.Acquired;

            Task.Factory.StartNew(
                SendHeartbeatsAsync,
                CancellationToken.None,
                TaskCreationOptions.LongRunning,
                TaskScheduler.Default);
        }
예제 #10
0
        private async Task <bool> AcquireLock(DistributedLockSettings settings, IServiceProvider serviceProvider)
        {
            var heartbeatThreshold = GetHeartbeatThreshold(settings.HeartbeatTimeout);

            var(dbSet, dbContext) = GetDbSet(serviceProvider);

            if (await dbSet.AsQueryable().AnyAsync(l => l.Name == settings.ResourceName && l.Heartbeat >= heartbeatThreshold))
            {
                return(false);
            }

            return(await WriteLock(settings.ResourceName, settings.UniqueId, heartbeatThreshold, dbSet, dbContext));
        }
        private async Task <bool> TryAcquireLockAsync(DistributedLockSettings settings)
        {
            try
            {
                using var scope = _serviceScopeFactory.CreateScope();
                return(await AcquireLockAsync(settings, scope.ServiceProvider).ConfigureAwait(false));
            }
            catch (Exception ex)
            {
                _logger.LogFailedToAcquireLock(settings, ex);
            }

            return(false);
        }
예제 #12
0
        private async Task <bool> TryAcquireLock(DistributedLockSettings settings)
        {
            try
            {
                using var scope = _serviceProvider.CreateScope();
                return(await AcquireLock(settings, scope.ServiceProvider));
            }
            catch (Exception ex)
            {
                _logger.LogDebug(ex, "Failed to acquire lock {lockName} ({lockUniqueId}). See inner exception for details.",
                                 settings.ResourceName, settings.UniqueId);
            }

            return(false);
        }
예제 #13
0
        public async Task Release(DistributedLockSettings settings)
        {
            try
            {
                using var scope = _serviceProvider.CreateScope();
                await Release(settings.ResourceName, settings.UniqueId, scope.ServiceProvider);

                _logger.LogInformation("Released lock {lockName} ({lockUniqueId}).", settings.ResourceName, settings.UniqueId);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(
                    ex, "Failed to release lock '{lockName} ({lockUniqueId})'. See inner exception for details.",
                    settings.ResourceName, settings.UniqueId);
            }
        }
예제 #14
0
        public async Task <bool> CheckIsStillLocked(DistributedLockSettings settings)
        {
            try
            {
                using var scope = _serviceProvider.CreateScope();
                return(await CheckIsStillLocked(settings.ResourceName, settings.UniqueId, settings.HeartbeatTimeout, scope.ServiceProvider));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex,
                                 "Failed to check lock {lockName} ({lockUniqueId}). See inner exception for details.",
                                 settings.ResourceName, settings.UniqueId);
            }

            return(false);
        }
        /// <inheritdoc cref="IDistributedLockManager.AcquireAsync" />
        public async Task <DistributedLock?> AcquireAsync(
            DistributedLockSettings settings,
            CancellationToken cancellationToken = default)
        {
            Check.NotNull(settings, nameof(settings));

            if (string.IsNullOrEmpty(settings.ResourceName))
            {
                throw new InvalidOperationException(
                          "ResourceName cannot be null. Please provide a valid resource name in the settings.");
            }

            if (settings is NullLockSettings)
            {
                return(await NullLockManager.AcquireAsync(settings, cancellationToken).ConfigureAwait(false));
            }

            _logger.LogInformation(
                CoreEventIds.AcquiringDistributedLock,
                "Trying to acquire lock {lockName} ({lockUniqueId})...",
                settings.ResourceName,
                settings.UniqueId);

            var stopwatch = Stopwatch.StartNew();

            while (settings.AcquireTimeout == null || stopwatch.Elapsed < settings.AcquireTimeout)
            {
                if (await TryAcquireLockAsync(settings).ConfigureAwait(false))
                {
                    _logger.LogInformation(
                        CoreEventIds.DistributedLockAcquired,
                        "Acquired lock {lockName} ({lockUniqueId}).",
                        settings.ResourceName,
                        settings.UniqueId);
                    return(new DistributedLock(settings, this));
                }

                await Task.Delay(settings.AcquireRetryInterval, cancellationToken).ConfigureAwait(false);

                if (cancellationToken.IsCancellationRequested)
                {
                    break;
                }
            }

            throw new TimeoutException($"Timeout waiting to get the required lock '{settings.ResourceName}'.");
        }
예제 #16
0
        public async Task <bool> SendHeartbeat(DistributedLockSettings settings)
        {
            try

            {
                using var scope = _serviceProvider.CreateScope();
                return(await SendHeartbeat(settings.ResourceName, settings.UniqueId, scope.ServiceProvider));
            }
            catch (Exception ex)
            {
                _logger.LogDebug(ex,
                                 "Failed to send heartbeat for lock {lockName} ({lockUniqueId}). See inner exception for details.",
                                 settings.ResourceName, settings.UniqueId);

                return(false);
            }
        }
        public async Task ReleaseAsync(DistributedLockSettings settings)
        {
            Check.NotNull(settings, nameof(settings));

            if (settings is NullLockSettings)
            {
                await NullLockManager.ReleaseAsync(settings).ConfigureAwait(false);
            }

            var tryCount = 1;

            while (tryCount <= 3)
            {
                try
                {
                    using var scope = _serviceScopeFactory.CreateScope();
                    await ReleaseAsync(settings.ResourceName, settings.UniqueId, scope.ServiceProvider)
                    .ConfigureAwait(false);

                    _logger.LogInformation(
                        CoreEventIds.DistributedLockReleased,
                        "Released lock {lockName} ({lockUniqueId}).",
                        settings.ResourceName,
                        settings.UniqueId);

                    break;
                }
                catch (Exception ex)
                {
                    _logger.LogWarning(
                        CoreEventIds.FailedToReleaseDistributedLock,
                        ex,
                        "Failed to release lock '{lockName} ({lockUniqueId})'. See inner exception for details.",
                        settings.ResourceName,
                        settings.UniqueId);

                    tryCount++;
                }
            }
        }
예제 #18
0
 protected DistributedBackgroundService(DistributedLockSettings distributedLockSettings, IDistributedLockManager distributedLockManager, ILogger <DistributedBackgroundService> logger)
 {
     _distributedLockSettings = distributedLockSettings ?? throw new ArgumentNullException(nameof(distributedLockSettings));
     _distributedLockManager  = distributedLockManager ?? throw new ArgumentNullException(nameof(distributedLockManager));
     _logger = logger;
 }
 protected RecurringDistributedBackgroundService(TimeSpan interval, DistributedLockSettings distributedLockSettings, IDistributedLockManager distributedLockManager, ILogger <RecurringDistributedBackgroundService> logger)
     : base(distributedLockSettings, distributedLockManager, logger)
 {
     _interval = interval;
     _logger   = logger;
 }
예제 #20
0
 public Task <DistributedLock> Acquire(DistributedLockSettings settings, CancellationToken cancellationToken = default) =>
 Task.FromResult <DistributedLock>(null);
예제 #21
0
 public Task <bool> CheckIsStillLocked(DistributedLockSettings settings) =>
 Task.FromResult(true);
예제 #22
0
 public Task <bool> SendHeartbeat(DistributedLockSettings settings) =>
 Task.FromResult(true);
예제 #23
0
 public Task Release(DistributedLockSettings settings) =>
 Task.CompletedTask;
예제 #24
0
 public Task <DistributedLock> Acquire(DistributedLockSettings settings, CancellationToken cancellationToken = default) =>
 Acquire(settings.ResourceName, settings.AcquireTimeout, settings.AcquireRetryInterval, settings.HeartbeatTimeout, cancellationToken);