Lyo.Lock
1.0.1
dotnet add package Lyo.Lock --version 1.0.1
NuGet\Install-Package Lyo.Lock -Version 1.0.1
<PackageReference Include="Lyo.Lock" Version="1.0.1" />
<PackageVersion Include="Lyo.Lock" Version="1.0.1" />
<PackageReference Include="Lyo.Lock" />
paket add Lyo.Lock --version 1.0.1
#r "nuget: Lyo.Lock, 1.0.1"
#:package Lyo.Lock@1.0.1
#addin nuget:?package=Lyo.Lock&version=1.0.1
#tool nuget:?package=Lyo.Lock&version=1.0.1
Lyo.Lock
Key-based exclusive locks and keyed semaphores (bounded concurrency per key) with a small abstraction layer and in-memory implementations for a single process.
Features
ILockService— acquire/release by string key, orExecuteWithLockAsynchelpers that throwTimeoutExceptionif the lock is not obtained.LocalLockService— one holder per normalized key usingSemaphoreSlim.IKeyedSemaphoreService— up tomaxConcurrencysimultaneous permit holders per key.LocalKeyedSemaphoreService— per-keySemaphoreSlimwith ref-counted cleanup when idle.- Key normalization — by default keys are compared case-insensitively (
ToLowerInvariant); optional skip when keys are already normalized. - DI —
AddLocalLock,AddLocalLockFromConfiguration,AddLocalKeyedSemaphore,AddLocalKeyedSemaphoreFromConfiguration. - Metrics — optional timers/counters via
Lyo.MetricswhenEnableMetricsis true andIMetricsis registered.
Examples
Quick start
using Lyo.Lock;
using Microsoft.Extensions.DependencyInjection;
services.AddLocalLock();
services.AddLocalKeyedSemaphore();
// Optional: bind appsettings → LockOptions / KeyedSemaphoreOptions
services.AddLocalLockFromConfiguration(configuration);
services.AddLocalKeyedSemaphoreFromConfiguration(configuration);
Quick start (2)
// Exclusive lock: null if timeout
var handle = await lockService.AcquireAsync("order:123", timeout: TimeSpan.FromSeconds(5));
if (handle is not null)
{
await using (handle)
await ProcessOrderAsync();
}
// Throws TimeoutException if not acquired
await lockService.ExecuteWithLockAsync("order:123", async ct => await ProcessOrderAsync(ct));
// Up to 3 concurrent operations for the same key (same process only)
await semaphoreService.ExecuteAsync("export:tenant-1", 3, async ct => await RunExportAsync(ct));
KeyedSemaphoreOptions (KeyedSemaphoreOptions section)
{
"LockOptions": {
"DefaultAcquireTimeout": "00:00:30",
"DefaultLockDuration": "00:01:00",
"KeyPrefix": "lyo:lock:",
"EnableMetrics": false,
"SkipKeyNormalization": false
},
"KeyedSemaphoreOptions": {
"DefaultAcquireTimeout": "00:00:30",
"SkipKeyNormalization": false,
"EnableMetrics": false
}
}
Benchmarks
- Portfolio suite:
lock
When to use what
| Primitive | Type | Scope | Typical use |
|---|---|---|---|
ILockService / LocalLockService |
Mutex per key | One process | Guard mutations to one aggregate, avoid duplicate work, serialize handlers per entity ID |
IKeyedSemaphoreService / LocalKeyedSemaphoreService |
Counting semaphore per key | One process | Cap concurrent exports/API calls/backfills per tenant or resource key without global rate limits |
For multiple servers or processes, register a distributed ILockService (see Lyo.Lock.Redis). Keyed semaphores in this package remain local
only.
Quick start
Inject ILockService and/or IKeyedSemaphoreService:
Rules for keyed semaphores
- Use a stable
maxConcurrencyfor a given key while any permit is held or waiters exist. If you pass a differentmaxConcurrencyfor an active key,LocalKeyedSemaphoreServicethrows (InvalidOperationException) instead of undefined behavior. - Cancellation tokens on
AcquireAsync/ExecuteAsyncare honored while waiting.
LockOptions (LockOptions section)
| Property | Default | Description |
|---|---|---|
DefaultAcquireTimeout |
30s | Max wait for AcquireAsync / ExecuteWithLockAsync. |
DefaultLockDuration |
60s | Used by distributed locks (Redis TTL). Ignored by LocalLockService. |
KeyPrefix |
lyo:lock: |
Prefix for Redis keys; harmless for local-only usage. |
SkipKeyNormalization |
false |
When true, keys are not lowercased (caller must ensure consistent casing). |
EnableMetrics |
false |
Record lock timings/counters when IMetrics is available. |
KeyedSemaphoreOptions (KeyedSemaphoreOptions section)
| Property | Default | Description |
|---|---|---|
DefaultAcquireTimeout |
30s | Max wait for a permit. |
SkipKeyNormalization |
false |
Same semantics as lock options. |
EnableMetrics |
false |
Record semaphore timings/counters when IMetrics is available. |
Example appsettings.json:
Metrics (Constants)
When metrics are enabled and IMetrics is registered, names match Lyo.Lock.Constants:
Locks (Constants.Metrics)
| Name | Role |
|---|---|
lock.acquire.duration |
Wait time for acquisition |
lock.acquire.success / lock.acquire.failure |
Counter |
lock.release.duration |
Release timing |
lock.execute.duration |
Wall time for ExecuteWithLockAsync |
Semaphores (Constants.SemaphoreMetrics)
| Name | Role |
|---|---|
semaphore.acquire.duration |
Wait time for a permit |
semaphore.acquire.success / semaphore.acquire.failure |
Counter |
semaphore.release.duration |
Release timing |
semaphore.execute.duration |
Wall time for ExecuteAsync |
Tag dimension: key — logical key string as passed by the caller (see XML docs on Constants).
API summary — ILockService
AcquireAsync— returnsILockHandle?(nullon timeout).ExecuteWithLockAsync/ExecuteWithLockAsync<T>— acquire, run delegate, release; throwTimeoutExceptionif not acquired.
API summary — ILockHandle / IPermitHandle
ReleaseAsync— idempotent after first release.Dispose/DisposeAsync— release (sync dispose may block briefly on internalReleaseAsync).
API summary — IKeyedSemaphoreService
AcquireAsync— returnsIPermitHandle?on timeout.ExecuteAsync/ExecuteAsync<T>— throwTimeoutExceptionif no permit.
Dependencies
Generated from ProjectReference / PackageReference (same model as docs/Lyo.ProjectGraph.html).
Lyo.Exceptions— (direct, lyo)Lyo.Metrics— (direct, lyo)Microsoft.Extensions.Configuration.Binder10.0.5— (direct, microsoft)Microsoft.Extensions.DependencyInjection.Abstractions10.0.5— (direct, microsoft)Microsoft.Extensions.Logging.Abstractions10.0.5— (direct, microsoft)Microsoft.Extensions.Options.ConfigurationExtensions10.0.5— (transitive, microsoft)
| 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 was computed. 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
- Lyo.Exceptions (>= 1.0.1)
- Lyo.Metrics (>= 1.0.1)
- Microsoft.Extensions.Configuration.Binder (>= 10.0.5)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
-
net10.0
- Lyo.Exceptions (>= 1.0.1)
- Lyo.Metrics (>= 1.0.1)
- Microsoft.Extensions.Configuration.Binder (>= 10.0.5)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Lyo.Lock:
| Package | Downloads |
|---|---|
|
Lyo.FileMetadataStore.Postgres
PostgreSQL implementation of the Lyo FileMetadataStore service using Entity Framework Core. |
|
|
Lyo.Lock.Redis
Redis-based distributed lock implementation for Lyo.Lock. Uses StackExchange.Redis for multi-instance coordination. |
|
|
Lyo.FileMetadataStore.Sqlite
SQLite implementation of the Lyo FileMetadataStore service using Entity Framework Core. |
GitHub repositories
This package is not used by any popular GitHub repositories.