Example #1
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>
 /// <returns>The task that represents the asynchronous operation result for running the specified delegate.</returns>
 public static Task ExclusiveRun(this ILockManager manager, string taskName, Func <CancellationToken, Task> task, CancellationToken cancellationToken) =>
 manager.ExclusiveRun(taskName, task, cancellationToken, ExclusiveRunOptions.Default());
Example #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();
        }