Overview
A distributed lock ensures that a critical section of code is executed by only one process at a time across multiple service instances. Silky provides Redis-based distributed locks via the Silky.DistributedLock.Redis package, built on top of RedLock.net.
Installation
<PackageReference Include="Silky.DistributedLock.Redis" Version="3.9.2" />
Setup
Module
[DependsOn(
typeof(RedisDistributedLockModule),
typeof(DotNettyTcpModule)
)]
public class OrderHostModule : SilkyModule { }
Configuration
{
"redisLock": {
"endpoints": [
{ "host": "127.0.0.1", "port": 6379 }
],
"password": "",
"database": 0,
"expiry": "00:00:30"
}
}
Using IDistributedLock
Inject IDistributedLock and use it to protect critical sections:
public class OrderAppService : IOrderAppService, IScopedDependency
{
private readonly IDistributedLock _distributedLock;
private readonly IOrderRepository _orderRepo;
public OrderAppService(
IDistributedLock distributedLock,
IOrderRepository orderRepo)
{
_distributedLock = distributedLock;
_orderRepo = orderRepo;
}
public async Task<CreateOrderOutput> CreateOrderAsync(CreateOrderInput input)
{
// Lock key is per-user to prevent double-submission
var lockKey = $"create-order:{input.UserId}";
await using (var handle = await _distributedLock.TryAcquireAsync(lockKey, TimeSpan.FromSeconds(10)))
{
if (handle == null)
{
throw new BusinessException("Another order creation is in progress. Please try again later.");
}
// Critical section — only one instance executes this at a time
var order = new Order { UserId = input.UserId, /* ... */ };
await _orderRepo.InsertAsync(order);
return new CreateOrderOutput { OrderId = order.Id };
}
}
}
Async Lock with Timeout
// Wait up to 5 seconds to acquire the lock; expires after 30 seconds
await using var handle = await _distributedLock.TryAcquireAsync(
resource: "inventory:update",
expiry: TimeSpan.FromSeconds(30),
wait: TimeSpan.FromSeconds(5),
retry: TimeSpan.FromMilliseconds(200));
if (handle == null)
{
// Could not acquire within the wait period
throw new TimeoutException("Could not acquire distributed lock");
}
Parameters
| Parameter | Description | Default |
|---|---|---|
resource | Unique lock key | (required) |
expiry | Lock TTL — auto-released after this time | 30s |
wait | Max time to wait for the lock | 10s |
retry | Retry interval while waiting | 200ms |
Multi-Node (RedLock Algorithm)
For high availability, configure multiple Redis endpoints. The lock is acquired using the RedLock algorithm — requiring a majority of nodes to agree:
{
"redisLock": {
"endpoints": [
{ "host": "redis-1", "port": 6379 },
{ "host": "redis-2", "port": 6379 },
{ "host": "redis-3", "port": 6379 }
]
}
}
