private async Task RunTaskWhenBlobLeaseAcquired(BlobLeaseManager leaseManager, CancellationToken token) { while (!token.IsCancellationRequested) { // Try to acquire the blob lease, otherwise wait for some time before we can try again. var leaseId = await TryAcquireLeaseOrWait(leaseManager, token); if (!string.IsNullOrEmpty(leaseId)) { // 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. using (var leaseCts = CancellationTokenSource.CreateLinkedTokenSource(token)) { // Run the leader task. var leaderTask = taskToRunWhenLeaseAcquired.Invoke(leaseCts.Token); // Keeps renewing the lease in regular intervals. // If the lease cannot be renewed, then the task completes. var renewLeaseTask = KeepRenewingLease(leaseManager, leaseId, leaseCts.Token); // When any task completes (either the leader task or when it could // not renew the lease) then cancel the other task. await CancelAllWhenAnyCompletes(leaderTask, renewLeaseTask, leaseCts); } } } }
private async Task KeepRenewingLease(BlobLeaseManager leaseManager, string leaseId, CancellationToken token) { var renewOffset = new Stopwatch(); while (!token.IsCancellationRequested) { try { // Immediately attempt to renew the lease // We cannot be sure how much time has passed since the lease was actually acquired renewOffset.Restart(); var renewed = await leaseManager.RenewLeaseAsync(leaseId, token); renewOffset.Stop(); if (!renewed) { logger.LogWarning("Mutex lost"); return; } logger.LogDebug("Mutex renewed"); // We delay based on the time from the start of the last renew request to ensure var renewIntervalAdjusted = RenewInterval - renewOffset.Elapsed; // If the adjusted interval is greater than zero wait for that long if (renewIntervalAdjusted > TimeSpan.Zero) { await Task.Delay(RenewInterval - renewOffset.Elapsed, token); } } catch (OperationCanceledException) { await leaseManager.ReleaseLeaseAsync(leaseId); } } }
private async Task <string> TryAcquireLeaseOrWait(BlobLeaseManager leaseManager, CancellationToken token) { try { logger.LogInformation("Attepting to acquire mutex..."); var leaseId = await leaseManager.AcquireLeaseAsync(token); if (!string.IsNullOrEmpty(leaseId)) { logger.LogInformation("Mutex acquired"); return(leaseId); } await Task.Delay(AcquireAttemptInterval, token); return(null); } catch (OperationCanceledException) { return(null); } }
public Task RunTaskWhenMutexAcquired(CancellationToken token) { var leaseManager = new BlobLeaseManager(blobSettings, logger); return(RunTaskWhenBlobLeaseAcquired(leaseManager, token)); }