Wiaoj.DistributedCounter
0.1.0-alpha.7
This is a prerelease version of Wiaoj.DistributedCounter.
dotnet add package Wiaoj.DistributedCounter --version 0.1.0-alpha.7
NuGet\Install-Package Wiaoj.DistributedCounter -Version 0.1.0-alpha.7
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Wiaoj.DistributedCounter" Version="0.1.0-alpha.7" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Wiaoj.DistributedCounter" Version="0.1.0-alpha.7" />
<PackageReference Include="Wiaoj.DistributedCounter" />
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Wiaoj.DistributedCounter --version 0.1.0-alpha.7
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Wiaoj.DistributedCounter, 0.1.0-alpha.7"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Wiaoj.DistributedCounter@0.1.0-alpha.7
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Wiaoj.DistributedCounter&version=0.1.0-alpha.7&prerelease
#tool nuget:?package=Wiaoj.DistributedCounter&version=0.1.0-alpha.7&prerelease
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Wiaoj.DistributedCounter
The core runtime engine, in-memory storage provider, background synchronization service, and dependency injection integration for the Wiaoj.DistributedCounter library.
Installation
dotnet add package Wiaoj.DistributedCounter
What This Package Contains
DistributedCounterFactory: Resolves and caches counter instances (IDistributedCounter) by name or marker tag (TTag), applying configured synchronization strategies and dedicated storage backends.TypedDistributedCounterWrapper<TTag>: Generic wrapper registered in DI asIDistributedCounter<TTag>, delegating operations to factory-resolved counters and supporting sub-key scoping (.ForKey(key)).InMemoryCounterStorage: Thread-safeICounterStorageimplementation usingConcurrentDictionary,TimeProvider-based sliding expiration, and CAS (Compare-And-Swap) loops for quota checks.CounterAutoFlushService: AnIHostedServicebackground worker that periodically collects pending in-memory deltas from buffered counters and executes batch writes against their respective storage providers.DistributedCounterService: Service for batch counter queries (GetValuesAsync), manual flush triggers (FlushAllAsync), and system-wide resets (ResetAllAsync).- Object Pool Integration: Reuses internal
Dictionary<string, CounterValue>buffers viaWiaoj.ObjectPoolto reduce heap allocations on batch retrieval paths.
Dependency Injection Setup
Basic Registration (In-Memory)
using Wiaoj.DistributedCounter;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDistributedCounter(counter => {
// Set in-memory storage as default backend
counter.UseInMemory();
// Enable background periodic auto-flush for buffered counters
counter.AddAutoFlush();
// Register an immediate counter (direct storage writes)
counter.AddImmediateCounter<RateLimitTag>();
// Register a buffered counter (in-memory aggregation with periodic flush)
counter.AddBufferedCounter<PageViewsTag>();
});
Configuration Options
builder.Services.AddDistributedCounter(counter => {
counter.Configure(options => {
options.GlobalKeyPrefix = "app:counters:";
options.DefaultStrategy = CounterStrategy.Buffered;
options.AutoFlushInterval = TimeSpan.FromSeconds(5);
});
counter.UseInMemory();
counter.AddAutoFlush();
// Per-tag strategy and storage overrides
counter.AddCounter<SecurityTag>(cfg => {
cfg.Strategy = CounterStrategy.Immediate;
cfg.UseInMemory();
});
});
Synchronization Strategies
1. Immediate (ImmediateDistributedCounter)
- Every call to
IncrementAsync,DecrementAsync,TryIncrementAsync,TryDecrementAsync,SetAsync, orResetAsyncexecutes directly against the configuredICounterStorage. - Recommended for rate limiting, quotas, and scenarios requiring absolute cross-instance consistency.
2. Buffered (BufferedDistributedCounter)
- Calls to
IncrementAsyncandDecrementAsyncupdate a local delta in memory using atomic operations (Interlocked). - Calls to
GetValueAsyncreturn the cached base value plus local pending deltas. - Calls to
TryIncrementAsyncorTryDecrementAsyncfirst force a local flush to storage, then evaluate the limit remotely. - Pending deltas are collected and committed in batches by
CounterAutoFlushService. - If an external process changes the remote value, the counter detects the drift during flush response synchronization and adjusts its local base value (self-healing).
- If a storage flush fails, the uncommitted local delta is rolled back into memory to prevent data loss.
In-Memory Storage (InMemoryCounterStorage)
InMemoryCounterStorage provides a standalone storage backend without external dependencies:
- Sliding Expiration: Tracks expiration timestamps per key relative to the injected
TimeProvider. - Atomic Quota Checks: Implements
TryIncrementAsyncandTryDecrementAsyncvia lock-free update loops onConcurrentDictionary. - Batch Operations: Implements
BatchIncrementAsyncandGetManyAsyncfor multi-key updates and queries.
// Standalone usage outside Microsoft DI
TimeProvider timeProvider = TimeProvider.System;
ICounterStorage storage = new InMemoryCounterStorage(timeProvider);
CounterKey key = new("test:key");
await storage.AtomicIncrementAsync(key, 1, CounterExpiry.FromMinutes(1), CancellationToken.None);
Background Worker (CounterAutoFlushService)
When enabled via .AddAutoFlush(), CounterAutoFlushService:
- Runs on a
PeriodicTimerdriven byoptions.AutoFlushIntervalandTimeProvider. - Gathers all active
BufferedDistributedCounterinstances fromIBufferedCounterSource. - Groups counters by their assigned
ICounterStoragereference. - Rents array buffers from
ArrayPool<T>and executesBatchIncrementAsyncon each storage group. - Synchronizes resulting remote values with local counter base values.
- Performs a final batch flush when
StopAsyncis invoked during application shutdown.
Observability
OpenTelemetry Metrics (Wiaoj.DistributedCounter)
distributed_counter.increments(Counter<long>): Total increment calls (tags:distributed_counter.name,distributed_counter.strategy).distributed_counter.flushes(Counter<long>): Total background flush runs.distributed_counter.flush_duration(Histogram<double>inms): Batch flush execution duration.
OpenTelemetry Traces (Wiaoj.DistributedCounter)
FlushBatch: Activity wrapping the batch update extraction, serialization, and storage execution.SelfHealingDrift: Event attached to the activity when remote drift is detected.
License
This project is licensed under the MIT License.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
net10.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.2)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.2)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.2)
- Microsoft.Extensions.Options (>= 10.0.2)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.2)
- Wiaoj.Concurrency (>= 0.1.0-alpha.7)
- Wiaoj.DistributedCounter.Abstractions (>= 0.1.0-alpha.7)
- Wiaoj.Primitives (>= 0.1.0-alpha.7)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Wiaoj.DistributedCounter:
| Package | Downloads |
|---|---|
|
Wiaoj.DistributedCounter.Redis
Package Description |
|
|
Wiaoj.RateLimiting
Package Description |
|
|
Wiaoj.Resilience
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0-alpha.7 | 39 | 9/18/2026 |
| 0.1.0-alpha.6 | 50 | 9/16/2026 |
| 0.1.0-alpha.5 | 53 | 9/16/2026 |
| 0.1.0-alpha.4 | 51 | 9/16/2026 |
| 0.1.0-alpha.3 | 59 | 9/15/2026 |
| 0.1.0-alpha.2 | 95 | 9/15/2026 |
| 0.1.0-alpha.1 | 68 | 9/14/2026 |
| 0.0.1-alpha.112-preview | 66 | 9/13/2026 |
| 0.0.1-alpha.111-preview | 67 | 9/13/2026 |
| 0.0.1-alpha.110-preview | 69 | 9/12/2026 |
| 0.0.1-alpha.109-preview | 74 | 9/11/2026 |
| 0.0.1-alpha.108-preview | 84 | 9/8/2026 |
| 0.0.1-alpha.107-preview | 93 | 9/8/2026 |
| 0.0.1-alpha.106-preview | 79 | 9/8/2026 |
| 0.0.1-alpha.105-preview | 81 | 9/8/2026 |
| 0.0.1-alpha.104-preview | 86 | 9/7/2026 |
| 0.0.1-alpha.103-preview | 81 | 9/7/2026 |
| 0.0.1-alpha.102-preview | 81 | 9/6/2026 |
| 0.0.1-alpha.101-preview | 156 | 9/6/2026 |
| 0.0.1-alpha.100-preview | 73 | 9/6/2026 |
Loading failed