private async Task StartInternalAsync( string lockName, LockLostBehavior lockLostBehavior, CancellationToken cancellationToken) { _log.TraceMethodEntry(); if (cancellationToken.IsCancellationRequested) { return; } var lockTimeout = TimeSpan.FromSeconds(5); using (var inMemoryLockCacheClient = new InMemoryCacheClient()) using (var distributedLockCacheClient = new HybridCacheClient(inMemoryLockCacheClient, _messageBus)) { var lockProvider = new CacheLockProvider(distributedLockCacheClient, _messageBus); while (!cancellationToken.IsCancellationRequested) { var lockHandle = await lockProvider.AcquireAsync( lockName, lockTimeout, cancellationToken) .ConfigureAwait(false); if (lockHandle != null) { try { // we have the lock // keep renewing it await HoldAndRenewAsync( lockHandle, cancellationToken) .ConfigureAwait(false); } catch (Exception e) { switch (lockLostBehavior) { case LockLostBehavior.Complete: return; case LockLostBehavior.Error: throw new LockLostException(lockName, e); case LockLostBehavior.Retry: break; default: break; } } } } } }
/// <summary> /// Creates and starts a Distributed Lock Process Manager. /// </summary> /// <param name="messageBus">The message bus to attach to.</param> /// <param name="loggerFactory">The logging interface factory.</param> /// <param name="lockName">The name of the lock.</param> /// <param name="lockLostBehavior">The behavior to carry out if the lock is lost.</param> /// <param name="hasLockObserver">The observer for watching if the lock is aquired.</param> /// <param name="cancellationToken">The cancellation token used to stop the process manager.</param> /// <returns>Instance of the distributed lock process manager and the active task.</returns> public static (DistributedLockProcessManager Instance, Task Task, IDisposable HasLockSubscription) SubscribeAndStart( IMessageBus messageBus, ILoggerFactory loggerFactory, string lockName, LockLostBehavior lockLostBehavior, IObserver <bool> hasLockObserver, CancellationToken cancellationToken) { if (hasLockObserver == null) { throw new ArgumentNullException(nameof(hasLockObserver)); } var instance = new DistributedLockProcessManager( messageBus, lockName, lockLostBehavior, loggerFactory); var hasLockSubscription = instance.HasLock.Subscribe(hasLockObserver); var task = instance.StartAsync(cancellationToken); return(instance, task, hasLockSubscription); }
/// <summary> /// Initializes a new instance of the <see cref="DistributedLockProcessManager"/> class. /// </summary> /// <param name="messageBus">The message bus to attach to.</param> /// <param name="lockName">The name of the lock.</param> /// <param name="lockLostBehavior">The behavior to carry out if the lock is lost.</param> /// <param name="loggerFactory">The logging interface factory.</param> public DistributedLockProcessManager( IMessageBus messageBus, string lockName, LockLostBehavior lockLostBehavior, ILoggerFactory loggerFactory) { _messageBus = messageBus ?? throw new ArgumentNullException(nameof(messageBus)); if (string.IsNullOrWhiteSpace(lockName)) { throw new ArgumentNullException(nameof(lockName)); } _lockName = lockName; _lockLostBehaviour = lockLostBehavior; if (loggerFactory == null) { throw new ArgumentNullException(nameof(loggerFactory)); } _log = loggerFactory.CreateLogger <DistributedLockProcessManager>(); }