Skip to content

Instantly share code, notes, and snippets.

@mjul
Created November 21, 2018 08:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mjul/15827ed7ec7a27aa184fa8b5e87a657b to your computer and use it in GitHub Desktop.
Save mjul/15827ed7ec7a27aa184fa8b5e87a657b to your computer and use it in GitHub Desktop.
Azure StorageAccount ClobBlob leases - useful as semaphores for ensuring e.g. only on job is processing a given queue at a time
public class AzureStorageCloudBlobLease
{
private readonly CloudBlob blob;
private string leaseId;
public AzureStorageCloudBlobLease(CloudBlob blob)
{
this.blob = blob ?? throw new ArgumentNullException(nameof(blob));
}
public async Task AcquireAsync(TimeSpan leaseTime, TimeSpan maxWaitingTimeForLease)
{
var startTime = DateTime.UtcNow;
while (true)
{
var timedOut = DateTime.UtcNow > startTime.Add(maxWaitingTimeForLease);
try
{
leaseId = await blob.AcquireLeaseAsync(leaseTime, Guid.NewGuid().ToString());
break;
}
catch (StorageException sex) when (sex.RequestInformation.HttpStatusCode == (int)HttpStatusCode.Conflict)
{
if (!timedOut)
{
// Randomize the waking up times a bit for heijunka (平準化) (load-levelling)
Thread.Sleep(TimeSpan.FromMilliseconds(750 + new System.Random().Next(500)));
}
else
{
throw new ApplicationException("Could not acquire lease", sex);
}
}
}
}
public async Task RenewAsync()
{
AssertLeaseAcquired();
await blob.RenewLeaseAsync(AccessCondition.GenerateLeaseCondition(this.leaseId));
}
private void AssertLeaseAcquired()
{
if (leaseId is null) throw new InvalidOperationException("Lease not acquired");
}
public async Task ReleaseAsync()
{
if (leaseId is null) throw new InvalidOperationException("Lease not acquired");
await this.blob.ReleaseLeaseAsync(AccessCondition.GenerateLeaseCondition(this.leaseId));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment