Esempio n. 1
0
        /// <summary>
        /// Tries to acquire the lock indefinitely until the action succeeds.
        /// </summary>
        /// <param name="manager">The instance of <see cref="ILockManager"/>.</param>
        /// <param name="name">Topic or name.</param>
        /// <param name="retryAfter">Specifies the duration in seconds to wait for a particular retry attempt.</param>
        /// <param name="cancellationToken">Propagates notification that operations should be canceled.</param>
        /// <returns>The task that represents the asynchronous operation result for acquiring the lock.</returns>
        public static async Task <LockLeaseResult> TryAcquireLockForeverPolicy(this ILockManager manager, string name, int retryAfter = 3, CancellationToken cancellationToken = default)
        {
            var policy = Policy.HandleResult <LockLeaseResult>(lockLeaseResult => !lockLeaseResult.Ok)
                         .WaitAndRetryForeverAsync(retryAttempt => TimeSpan.FromSeconds(retryAfter));

            return(await policy.ExecuteAsync(token => manager.TryAcquireLock(name), cancellationToken));
        }
Esempio n. 2
0
        /// <summary>
        /// Uses a lease on a shared resource imposed by the <see cref="ILockManager"/> (i.e an Azure Storage blob or a shared file in a NFS) to provide a mechanism for implementing a shared, distributed mutex.
        /// </summary>
        /// <remarks>
        /// This mutex can be used to elect a leader among a group of role instances in an Azure cloud service or an on-premise infrastructure.
        /// The first role instance to acquire the lease is elected the leader, and remains the leader until it releases the lease or isn't able to renew the lease.
        /// </remarks>
        /// <param name="manager">The instance of <see cref="ILockManager"/>.</param>
        /// <param name="task">A task that references the code that the role instance should run if it successfully acquires the lease over the blob and is elected the leader.</param>
        /// <param name="taskName">A name for the task to run.</param>
        /// <param name="cancellationToken">Propagates notification that operations should be canceled.</param>
        /// <param name="options">Options for configuring the ExclusiveRun method.</param>
        /// <returns>The task that represents the asynchronous operation result for running the specified delegate.</returns>
        public static async Task ExclusiveRun(this ILockManager manager, string taskName, Func <CancellationToken, Task> task, CancellationToken cancellationToken, ExclusiveRunOptions options)
        {
            // Run in a while loop as long as cancellation has not been requested for the provided token.
            CancellationTokenSource linkedTokenSource = null;

            while (!(linkedTokenSource?.IsCancellationRequested ?? false))
            {
                // Try to acquire the lock.
                var lockResult = await manager.TryAcquireLock(taskName, duration : TimeSpan.FromSeconds(options.LockDuration), cancellationToken : cancellationToken);

                // If it is not possible to acquire the lock, wait for 30 seconds and try again. Being a leader requires patience and consistency :)
                if (!lockResult.Ok)
                {
                    if (options.RetryIntervalInSeconds.HasValue)
                    {
                        await Task.Delay(TimeSpan.FromSeconds(options.RetryIntervalInSeconds.Value), cancellationToken);

                        continue;
                    }
                    else
                    {
                        break;
                    }
                }
                // Create a new linked cancellation token source, so if either the original token is canceled or the lease cannot be renewed, then the leader task can be canceled.
                linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
                // The role instance that is executing the following code is now the leader.
                using (lockResult.Lock) {
                    // The leader task.
                    var leaderTask = task.Invoke(linkedTokenSource.Token);
                    // The renew lease task.
                    var renewLeaseTask = TryRenewUntilCancelled(lockResult.Lock, linkedTokenSource.Token, intervalInSeconds: (int)Math.Round((decimal)options.LockDuration * (2 / 3)));
                    // Wait for either of the two tasks to complete.
                    await Task.WhenAny(leaderTask, renewLeaseTask);
                }
                // Cancel the user's leader task or the renew lease task, as the current role instance is no longer the leader.
                linkedTokenSource.Cancel();
            }
            linkedTokenSource?.Dispose();
        }
Esempio n. 3
0
        public async Task AquireLockTest()
        {
            var duration = TimeSpan.FromSeconds(15);
            var name     = "constantinos"; // using a random name :)
            var @lock    = await _LockManager.AcquireLock(name, duration);

            await using (@lock) {
                await Task.Delay(TimeSpan.FromSeconds(0.5));
            }
            var @lock2 = await _LockManager.AcquireLock(name, duration);

            await using (@lock2) {
                await Task.Delay(TimeSpan.FromSeconds(0.5));
            }
            var result = await _LockManager.TryAcquireLock(name);

            if (result.Ok)
            {
                await using (result.Lock) {
                    await Task.Delay(TimeSpan.FromSeconds(0.5));
                }
            }
        }