public async Task <AsyncOperationResult> TryReleaseLockAsync(AzureBlobLockResult releaseLock) { try { AccessCondition acc = new AccessCondition(); acc.LeaseId = releaseLock.LeaseId; if (await releaseLock.Blob.ExistsAsync()) { await releaseLock.Blob.ReleaseLeaseAsync(acc, options : _blobRequestOptions, operationContext : null); releaseLock.BlobOperationToken.Cancel(); _logger.LogInformation("ReleaseLockAsync: ReleaseLeaseStatus: {LeaseReleased} on the {BlobUri}.", true, releaseLock.Blob.Uri); return(new AsyncOperationResult(true, null)); } else { return(new AsyncOperationResult(false, null)); } } catch (Exception exception) { // If it fails do not do anything - the lease will be released in 1 minute anyway _logger.LogWarning(LogEvents.FailedBlobReleaseLease, exception, "ReleaseLockAsync: Release lease failed for {BlobUri}.", true, releaseLock.Blob.Uri); return(new AsyncOperationResult(null, exception)); } }
/// <summary> /// Try to acquire a lease on the blob. If the acquire is successful the lease will be renewed at every 60 seconds. /// In order to stop the renew task the <see cref="Stats.AzureCdnLogs.Common.AzureBlobLeaseManager.TryReleaseLease(CloudBlob)"/> needs to be invoked /// or the token to be cancelled. /// </summary> /// <param name="blob">The blob to acquire the lease on.</param> /// <param name="token">A token to cancel the operation.</param> /// <param name="renewStatusTask">The renew task.</param> /// <returns>True if the lease was acquired. </returns> public AzureBlobLockResult AcquireLease(CloudBlob blob, CancellationToken token) { blob.FetchAttributes(); if (token.IsCancellationRequested || blob.Properties.LeaseStatus == LeaseStatus.Locked) { _logger.LogInformation("AcquireLease: The operation was cancelled or the blob lease is already taken. Blob {BlobUri}, Cancellation status {IsCancellationRequested}, BlobLeaseStatus {BlobLeaseStatus}.", blob.Uri.AbsoluteUri, token.IsCancellationRequested, blob.Properties.LeaseStatus); return(AzureBlobLockResult.FailedLockResult(blob)); } var proposedLeaseId = Guid.NewGuid().ToString(); var leaseId = blob.AcquireLease(TimeSpan.FromSeconds(MaxRenewPeriodInSeconds), proposedLeaseId); var lockResult = new AzureBlobLockResult(blob: blob, lockIsTaken: true, leaseId: leaseId, linkToken: token); //start a task that will renew the lease until the token is cancelled or the Release methods was invoked var renewStatusTask = new Task((lockresult) => { var blobLockResult = (AzureBlobLockResult)lockresult; _logger.LogInformation("RenewLeaseTask: Started for BlobUri {BlobUri}. ThreadId {ThreadId}. IsCancellationRequested {IsCancellationRequested}. LeaseId {LeaseId}", blob.Uri.AbsoluteUri, Thread.CurrentThread.ManagedThreadId, blobLockResult.BlobOperationToken.IsCancellationRequested, blobLockResult.LeaseId); int sleepBeforeRenewInSeconds = MaxRenewPeriodInSeconds - OverlapRenewPeriodInSeconds < 0 ? MaxRenewPeriodInSeconds : MaxRenewPeriodInSeconds - OverlapRenewPeriodInSeconds; if (!blobLockResult.BlobOperationToken.IsCancellationRequested) { while (!blobLockResult.BlobOperationToken.Token.IsCancellationRequested) { Thread.Sleep(sleepBeforeRenewInSeconds * 1000); //it will renew the lease only if the lease was not explicitly released try { if (!blobLockResult.Blob.Exists()) { blobLockResult.BlobOperationToken.Cancel(); break; } AccessCondition acc = new AccessCondition { LeaseId = blobLockResult.LeaseId }; blob.RenewLease(accessCondition: acc, options: _blobRequestOptions, operationContext: null); _logger.LogInformation("RenewLeaseTask: Lease was renewed for BlobUri {BlobUri} and LeaseId {LeaseId}.", blob.Uri.AbsoluteUri, blobLockResult.LeaseId); } catch (StorageException exception) { _logger.LogWarning(LogEvents.FailedBlobLease, exception, "RenewLeaseTask: The Lease could not be renewed for BlobUri {BlobUri}. ExpectedLeaseId {LeaseId}. CurrentLeaseId {CurrentLeaseId}.", blob.Uri.AbsoluteUri, leaseId, blobLockResult.LeaseId); blobLockResult.BlobOperationToken.Cancel(); break; } } } }, lockResult, TaskCreationOptions.LongRunning); renewStatusTask.Start(); return(lockResult); }