DistributedLeasing.Azure.Blob
5.1.0
dotnet add package DistributedLeasing.Azure.Blob --version 5.1.0
NuGet\Install-Package DistributedLeasing.Azure.Blob -Version 5.1.0
<PackageReference Include="DistributedLeasing.Azure.Blob" Version="5.1.0" />
<PackageVersion Include="DistributedLeasing.Azure.Blob" Version="5.1.0" />
<PackageReference Include="DistributedLeasing.Azure.Blob" />
paket add DistributedLeasing.Azure.Blob --version 5.1.0
#r "nuget: DistributedLeasing.Azure.Blob, 5.1.0"
#:package DistributedLeasing.Azure.Blob@5.1.0
#addin nuget:?package=DistributedLeasing.Azure.Blob&version=5.1.0
#tool nuget:?package=DistributedLeasing.Azure.Blob&version=5.1.0
DistributedLeasing.Azure.Blob
Azure Blob Storage distributed leasing provider for .NET
This package implements distributed leasing using native Azure Blob Storage lease capabilities. It leverages Azure's built-in pessimistic locking mechanism for reliable, cloud-native distributed coordination.
Features
✅ Native Azure Blob Leases - Uses Azure's built-in lease mechanism (no polling)
✅ Automatic Renewal - Background renewal keeps leases alive
✅ Managed Identity Support - First-class Azure authentication integration
✅ Metadata Storage - Store custom metadata with each lease
✅ High Reliability - Azure-guaranteed consistency and durability
✅ Simple Setup - Container auto-creation, minimal configuration
When to Use Azure Blob Leasing
Best For:
- Leader election in Azure-hosted applications
- Distributed lock coordination with moderate throughput
- Long-running exclusive processes (minutes to hours)
- Applications already using Azure Storage
- Multi-region deployments with single-region coordination
Consider Alternatives When:
- Need sub-second latency → Use Azure Redis
- Need global distribution → Use Azure Cosmos DB
- Need extremely high throughput (>1000 ops/sec per lease)
Installation
dotnet add package DistributedLeasing.Azure.Blob
This automatically includes DistributedLeasing.Abstractions with authentication and observability support.
Quick Start
Basic Usage with Managed Identity
using DistributedLeasing.Azure.Blob;
using Azure.Identity;
// Create provider with managed identity
var provider = new BlobLeaseProvider(new BlobLeaseProviderOptions
{
ContainerUri = new Uri("https://mystorageaccount.blob.core.windows.net/leases"),
Credential = new DefaultAzureCredential(),
CreateContainerIfNotExists = true
});
// Create lease manager for a specific resource
var leaseManager = await provider.CreateLeaseManagerAsync("my-resource-lock");
// Acquire lease
var lease = await leaseManager.AcquireAsync(TimeSpan.FromSeconds(60));
if (lease != null)
{
try
{
// Do work while holding the lease
Console.WriteLine($"Lease acquired: {lease.LeaseId}");
await DoExclusiveWorkAsync();
}
finally
{
// Always release when done
await lease.ReleaseAsync();
}
}
else
{
Console.WriteLine("Could not acquire lease - another instance holds it");
}
Non-Blocking Acquisition
// Try to acquire without waiting
var lease = await leaseManager.TryAcquireAsync(TimeSpan.FromSeconds(60));
if (lease == null)
{
// Lease is held by another instance - fail fast
Console.WriteLine("Lease unavailable");
return;
}
// Proceed with work
With Custom Metadata
var options = new BlobLeaseProviderOptions
{
ContainerUri = new Uri("https://mystorageaccount.blob.core.windows.net/leases"),
Credential = new DefaultAzureCredential(),
Metadata = new Dictionary<string, string>
{
["instance"] = Environment.MachineName,
["version"] = "1.2.3",
["region"] = "us-east-1"
}
};
var provider = new BlobLeaseProvider(options);
Metadata is automatically prefixed with lease_ and stored with the blob. Useful for debugging and monitoring.
Configuration
Authentication Options
Option 1: Managed Identity (Recommended for Azure)
using Azure.Identity;
var options = new BlobLeaseProviderOptions
{
ContainerUri = new Uri("https://mystorageaccount.blob.core.windows.net/leases"),
Credential = new DefaultAzureCredential()
};
Option 2: Connection String (Development)
var options = new BlobLeaseProviderOptions
{
ConnectionString = "DefaultEndpointsProtocol=https;AccountName=...",
ContainerName = "leases"
};
Option 3: Specific Managed Identity
var options = new BlobLeaseProviderOptions
{
ContainerUri = new Uri("https://mystorageaccount.blob.core.windows.net/leases"),
Credential = new ManagedIdentityCredential("client-id-of-user-assigned-identity")
};
For comprehensive authentication configuration (including Service Principal, Workload Identity, etc.), see Authentication Guide.
Provider Options
public class BlobLeaseProviderOptions
{
// Authentication (choose one)
public Uri? ContainerUri { get; set; }
public TokenCredential? Credential { get; set; }
public string? ConnectionString { get; set; }
public string? ContainerName { get; set; }
// Container behavior
public bool CreateContainerIfNotExists { get; set; } = true;
// Lease configuration
public LeaseOptions? LeaseOptions { get; set; }
// Custom metadata
public IDictionary<string, string>? Metadata { get; set; }
}
Lease Options
var leaseOptions = new LeaseOptions
{
DefaultLeaseDuration = TimeSpan.FromSeconds(60),
AutoRenew = true,
AutoRenewInterval = TimeSpan.FromSeconds(40),
MaxRetryAttempts = 3,
RetryDelay = TimeSpan.FromSeconds(2)
};
var providerOptions = new BlobLeaseProviderOptions
{
ContainerUri = containerUri,
Credential = credential,
LeaseOptions = leaseOptions
};
How Azure Blob Leasing Works
Blob Lease Mechanism
Azure Blob Storage provides native pessimistic locking through the lease API:
- Acquire: Application requests a lease on a blob for a specified duration (15-60 seconds)
- Lock: Azure grants an exclusive lease ID to the requester
- Renew: Lease holder periodically renews before expiration
- Release: Lease holder explicitly releases, or Azure auto-expires
Key Characteristics:
- Pessimistic Lock: Only one lease holder at a time
- Automatic Expiration: Azure guarantees lease expires if not renewed
- No Polling: Lease state is authoritative server-side
- High Reliability: Built on Azure Storage's consistency guarantees
Blob Naming Convention
Leases are stored as blobs with the naming pattern:
lease-{leaseKey}
Example:
- Lease key:
database-migration - Blob name:
lease-database-migration
Metadata Storage
Each lease blob stores metadata automatically:
| Metadata Key | Description | Example |
|---|---|---|
leaseName |
Original lease key | database-migration |
createdAt |
Blob creation time | 2025-12-25T12:00:00Z |
lastModified |
Last metadata update | 2025-12-25T12:05:30Z |
lease_* |
Custom user metadata | lease_instance: server-01 |
User-provided metadata is prefixed with lease_ to avoid conflicts.
Performance Characteristics
Latency
| Operation | Typical Latency | Notes |
|---|---|---|
| Acquire (success) | 50-150ms | Single HTTP request to Azure |
| Acquire (failure) | 50-150ms | Fast fail if unavailable |
| Renew | 50-150ms | Background operation |
| Release | 50-150ms | Single HTTP request |
Network Dependency: Latency varies by region and network conditions.
Throughput
- Single Lease: ~100-200 operations/second (acquire/renew/release combined)
- Multiple Leases: Scales linearly (each lease is independent blob)
- Concurrent Acquisitions: Azure serializes requests per blob
Best Practice: For high-throughput scenarios (>1000 ops/sec), use Azure Redis instead.
Lease Duration Limits
- Minimum: 15 seconds
- Maximum: 60 seconds
- Recommended: 30-60 seconds with renewal at 2/3 interval
Best Practices
1. Use Managed Identity in Production
// ✅ Good
var options = new BlobLeaseProviderOptions
{
ContainerUri = new Uri("https://mystorageaccount.blob.core.windows.net/leases"),
Credential = new DefaultAzureCredential()
};
// ❌ Avoid in production
var options = new BlobLeaseProviderOptions
{
ConnectionString = "DefaultEndpointsProtocol=https;AccountName=..."
};
2. Always Release Leases
// ✅ Good
var lease = await leaseManager.AcquireAsync();
try
{
await DoWorkAsync();
}
finally
{
await lease.ReleaseAsync(); // Always release
}
// ❌ Risky - lease may not be released
var lease = await leaseManager.AcquireAsync();
await DoWorkAsync();
3. Handle Lease Loss
var cts = new CancellationTokenSource();
lease.LeaseLost += (sender, e) =>
{
Console.WriteLine($"Lease lost: {e.Reason}");
cts.Cancel(); // Stop work immediately
};
try
{
await LongRunningWorkAsync(cts.Token);
}
finally
{
await lease.ReleaseAsync();
}
4. Use Appropriate Lease Duration
// ✅ For short tasks (seconds to minutes)
var lease = await leaseManager.AcquireAsync(TimeSpan.FromSeconds(30));
// ✅ For longer tasks (minutes to hours)
// Auto-renewal keeps it alive
var lease = await leaseManager.AcquireAsync(TimeSpan.FromSeconds(60));
5. Add Metadata for Debugging
var options = new BlobLeaseProviderOptions
{
ContainerUri = containerUri,
Credential = credential,
Metadata = new Dictionary<string, string>
{
["instance"] = Environment.MachineName,
["process"] = Process.GetCurrentProcess().Id.ToString(),
["started"] = DateTime.UtcNow.ToString("o")
}
};
Troubleshooting
"Container does not exist"
Problem: Container not created or wrong name.
Solution:
var options = new BlobLeaseProviderOptions
{
ContainerUri = containerUri,
Credential = credential,
CreateContainerIfNotExists = true // Enable auto-creation
};
"Authentication failed"
Problem: Managed identity not configured or insufficient permissions.
Solution:
- Ensure managed identity is enabled on the Azure resource
- Assign "Storage Blob Data Contributor" role to the identity
- Verify container URI is correct
"Lease already exists" on acquire
Problem: Another instance holds the lease (expected behavior).
Solution: This is not an error - it's the distributed lock working correctly. Use TryAcquireAsync() for non-blocking behavior.
Frequent renewal failures
Problem: Network latency or lease duration too short.
Solution:
var leaseOptions = new LeaseOptions
{
DefaultLeaseDuration = TimeSpan.FromSeconds(60), // Increase duration
AutoRenewInterval = TimeSpan.FromSeconds(40) // 2/3 of duration
};
Lease not released after application crash
Problem: Application terminated before releasing lease.
Solution: This is expected - Azure automatically expires the lease after the duration. Wait for expiration (max 60 seconds) before next acquisition.
Monitoring and Observability
Inspect Lease State with Azure CLI
# List all lease blobs
az storage blob list \
--account-name mystorageaccount \
--container-name leases \
--output table
# Show lease metadata
az storage blob metadata show \
--account-name mystorageaccount \
--container-name leases \
--name lease-my-resource-lock
# Check lease status
az storage blob show \
--account-name mystorageaccount \
--container-name leases \
--name lease-my-resource-lock \
--query "properties.lease"
Metrics and Health Checks
See DistributedLeasing.Abstractions README for:
- OpenTelemetry metrics configuration
- Health check setup
- Distributed tracing integration
Samples
For comprehensive examples with real-world scenarios, see:
- BlobLeaseSample - Complete distributed lock competition demo
- Multiple instance competition
- Automatic renewal examples
- Metadata inspection
- Troubleshooting scenarios
Architecture
┌─────────────────────────────────────────────────────┐
│ Your Application │
│ ┌──────────────┐ ┌─────────────────┐ │
│ │ ILeaseProvider│────────▶│ BlobLeaseProvider│ │
│ └──────────────┘ └─────────────────┘ │
│ │ │
│ │ CreateLeaseManagerAsync("my-lock") │
│ ▼ │
│ ┌──────────────┐ ┌──────────────────┐ │
│ │ILeaseManager │────────▶│ BlobLeaseManager │ │
│ └──────────────┘ └──────────────────┘ │
│ │ │
│ │ AcquireAsync() │
│ ▼ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ ILease │────────▶│ BlobLease │ │
│ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────┘
│
│ Azure Blob Storage API
▼
┌─────────────────────────────────────────────────────┐
│ Azure Blob Storage │
│ ┌─────────────────────────────────────────────┐ │
│ │ Container: leases │ │
│ │ ┌─────────────────────────────────────┐ │ │
│ │ │ Blob: lease-my-lock │ │ │
│ │ │ • Lease ID: abc123... │ │ │
│ │ │ • State: Leased │ │ │
│ │ │ • Duration: 60s │ │ │
│ │ │ • Metadata: │ │ │
│ │ │ - lease_instance: server-01 │ │ │
│ │ │ - lease_region: us-east │ │ │
│ │ └─────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
Framework Compatibility
- .NET Standard 2.0 - Compatible with .NET Framework 4.6.1+, .NET Core 2.0+
- .NET 8.0 - Long-term support release
- .NET 10.0 - Latest release
Package Dependencies
- DistributedLeasing.Abstractions - Core framework
- Azure.Storage.Blobs - Azure Blob Storage SDK
- Azure.Identity - Azure authentication
Related Packages
- DistributedLeasing.Azure.Cosmos - Cosmos DB provider (global distribution)
- DistributedLeasing.Azure.Redis - Redis provider (low latency)
- DistributedLeasing.ChaosEngineering - Testing utilities
Documentation
License
MIT License - see LICENSE for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Azure.Identity (>= 1.17.1)
- Azure.Storage.Blobs (>= 12.26.0)
- DistributedLeasing.Abstractions (>= 5.1.0)
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.1)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.1)
-
net10.0
- Azure.Identity (>= 1.17.1)
- Azure.Storage.Blobs (>= 12.26.0)
- DistributedLeasing.Abstractions (>= 5.1.0)
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.1)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.1)
-
net8.0
- Azure.Identity (>= 1.17.1)
- Azure.Storage.Blobs (>= 12.26.0)
- DistributedLeasing.Abstractions (>= 5.1.0)
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.1)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.1)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on DistributedLeasing.Azure.Blob:
| Package | Downloads |
|---|---|
|
DistributedLeasing.Extensions.DependencyInjection
Dependency injection extensions for the DistributedLeasing library. Provides service registration helpers for ASP.NET Core and other DI-enabled applications. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Minor version 5.1: Added Redis distributed locking sample with comprehensive documentation, enhanced setup-resources.sh script with --project argument supporting blob/cosmos/redis selection, interactive configuration wizard for all samples. Includes RedisLeaseSample demonstrating atomic SET NX operations, lock competition, and metadata inspection. No breaking API changes - safe to upgrade from 5.0.x.