ManagedCode.TimeSeries
0.0.20
Prefix Reserved
dotnet add package ManagedCode.TimeSeries --version 0.0.20
NuGet\Install-Package ManagedCode.TimeSeries -Version 0.0.20
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="ManagedCode.TimeSeries" Version="0.0.20" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ManagedCode.TimeSeries" Version="0.0.20" />
<PackageReference Include="ManagedCode.TimeSeries" />
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 ManagedCode.TimeSeries --version 0.0.20
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: ManagedCode.TimeSeries, 0.0.20"
#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 ManagedCode.TimeSeries@0.0.20
#: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=ManagedCode.TimeSeries&version=0.0.20
#tool nuget:?package=ManagedCode.TimeSeries&version=0.0.20
The NuGet Team does not provide support for this client. Please contact its maintainers for support.

ManagedCode.TimeSeries
Lock-free, allocation-conscious time-series primitives written in modern C# for building fast counters, aggregations, and rolling analytics.
| Package | NuGet |
|---|---|
| Core library |
Why TimeSeries?
- Data pipelines demand concurrency. We built the core on lock-free
ConcurrentDictionary/ConcurrentQueuestructures and custom atomic helpers, so write-heavy workloads scale across cores without blocking. - Numeric algorithms shouldn’t duplicate code. Everything is generic over
INumber<T>, soint,decimal, or your own numeric type can use the same summer/accumulator implementations. - Hundreds of signals, one API. Grouped accumulators and summers make it trivial to manage keyed windows (think “per customer”, “per endpoint”, “per shard”) with automatic clean-up.
- Production-ready plumbing. Orleans converters, Release automation, Coveralls reporting, and central package management are all wired up out of the box.
Table of Contents
- Feature Highlights
- Quickstart
- Architecture Notes
- Development Workflow
- Release Automation
- Extensibility
- Contributing
- License
Feature Highlights
- Lock-free core – writes hit
ConcurrentDictionary+ConcurrentQueue, range metadata updated via custom atomics. - Generic summers –
NumberTimeSeriesSummer<T>& friends operate on anyINumber<T>implementation. - Mass fan-in ready – grouped accumulators/summers handle hundreds of keys without
lock. - Orleans-native – converters bridge to Orleans surrogates so grains can persist accumulators out of the box.
- Delivery pipeline – GitHub Actions release workflow bundles builds, tests, packs, tagging, and publishing.
- Central package versions – single source of NuGet truth via
Directory.Packages.props.
Quickstart
Install
dotnet add package ManagedCode.TimeSeries
Create a rolling accumulator
using ManagedCode.TimeSeries.Accumulators;
var requests = new IntTimeSeriesAccumulator(TimeSpan.FromSeconds(5), maxSamplesCount: 60);
Parallel.For(0, 10_000, i =>
{
requests.AddNewData(i);
});
Console.WriteLine($"Samples stored: {requests.Samples.Count}");
Console.WriteLine($"Events processed: {requests.DataCount}");
Summaries with any numeric type
using ManagedCode.TimeSeries.Summers;
var latency = new NumberTimeSeriesSummer<decimal>(TimeSpan.FromMilliseconds(500));
latency.AddNewData(DateTimeOffset.UtcNow, 12.4m);
latency.AddNewData(DateTimeOffset.UtcNow.AddMilliseconds(250), 9.6m);
Console.WriteLine($"AVG: {latency.Average():F2} ms");
Console.WriteLine($"P50/P100: {latency.Min()} / {latency.Max()}");
Track many signals at once
using ManagedCode.TimeSeries.Accumulators;
var perEndpoint = new IntGroupTimeSeriesAccumulator(
sampleInterval: TimeSpan.FromSeconds(1),
maxSamplesCount: 300,
deleteOverdueSamples: true);
Parallel.ForEach(requests, req =>
{
perEndpoint.AddNewData(req.Path, req.Timestamp, 1);
});
foreach (var (endpoint, accumulator) in perEndpoint.Snapshot())
{
Console.WriteLine($"{endpoint}: {accumulator.DataCount} hits");
}
Orleans-friendly serialization
// In your Orleans silo:
builder.Services.AddSerializer(builder =>
{
builder.AddConverter<IntTimeSeriesAccumulatorConverter<int>>();
builder.AddConverter<IntTimeSeriesSummerConverter<int>>();
// …add others as needed
});
Architecture Notes
- Lock-free core:
BaseTimeSeriesstores samples in aConcurrentDictionaryand updates range metadata throughAtomicDateTimeOffset. Per-key data is aConcurrentQueue<T>(accumulators) or directINumber<T>(summers). - Deterministic reads: consumers get an ordered read-only projection of the concurrent map, so existing iteration/test semantics stay intact while writers remain lock-free.
- Group managers:
BaseGroupTimeSeriesAccumulatorandBaseGroupNumberTimeSeriesSummeruseConcurrentDictionary<string, ...>plus lightweight background timers for overdue clean-up—nolockstatements anywhere on the hot path. - Orleans bridge: converters project between the concurrent structures and Orleans’ plain dictionaries/queues, keeping serialized payloads simple while the live types stay lock-free.
Extensibility
| Scenario | Hook |
|---|---|
| Custom numeric type | Implement INumber<T> and plug into NumberTimeSeriesSummer<T> |
| Alternative aggregation strategy | Extend Strategy enum & override Update in a derived summer |
| Domain-specific accumulator | Derive from TimeSeriesAccumulator<T, TSelf> (future rename of BaseTimeSeriesAccumulator) and expose tailored helpers |
| Serialization | Add dedicated Orleans converters / System.Text.Json converters using the pattern in ManagedCode.TimeSeries.Orleans |
Heads up: the
Base*prefixes hang around for historical reasons. We plan to rename the concrete-ready generics toTimeSeriesAccumulator<T,...>/TimeSeriesSummer<T,...>in a future release with deprecation shims.
Development Workflow
- Solution:
ManagedCode.TimeSeries.slnxdotnet restore ManagedCode.TimeSeries.slnx dotnet build ManagedCode.TimeSeries.slnx --configuration Release dotnet test ManagedCode.TimeSeries.Tests/ManagedCode.TimeSeries.Tests.csproj --configuration Release - Packages: update versions only in
Directory.Packages.props. - Coverage:
dotnet test ... -p:CollectCoverage=true -p:CoverletOutputFormat=lcov. - Benchmarks:
dotnet run --project ManagedCode.TimeSeries.Benchmark --configuration Release.
Release Automation
- Workflow:
.github/workflows/release.yml- Trigger: push to
mainor manualworkflow_dispatch. - Steps: restore → build → test → pack →
dotnet nuget push(skip duplicates) → create/tag release. - Configure secrets:
NUGET_API_KEY: NuGet publish token.- Default
${{ secrets.GITHUB_TOKEN }}is used for tagging and releases.
- Trigger: push to
Contributing
- Restore/build/test using the commands above.
- Keep new APIs covered with tests (see existing samples in
ManagedCode.TimeSeries.Tests). - Align with the lock-free architecture—avoid introducing
lockon hot paths. - Document new features in this README.
License
MIT © ManagedCode SAS.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. 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 was computed. 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.
-
net9.0
- No dependencies.
NuGet packages (3)
Showing the top 3 NuGet packages that depend on ManagedCode.TimeSeries:
| Package | Downloads |
|---|---|
|
ManagedCode.Keda.Orleans.Scaler.Client
Keda |
|
|
ManagedCode.Keda.Orleans.Scaler
Keda |
|
|
ManagedCode.TimeSeries.Orleans
TimeSeries |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.0.20 | 168 | 10/19/2025 |
| 0.0.18 | 784 | 5/17/2023 |
| 0.0.17 | 12,254 | 12/9/2022 |
| 0.0.16 | 399 | 12/9/2022 |
| 0.0.15 | 416 | 12/9/2022 |
| 0.0.12 | 1,974 | 10/11/2022 |
| 0.0.11 | 510 | 10/11/2022 |
| 0.0.10 | 805 | 10/10/2022 |
| 0.0.9 | 1,273 | 10/10/2022 |
| 0.0.8 | 751 | 10/10/2022 |
| 0.0.7 | 757 | 10/10/2022 |
| 0.0.6 | 1,319 | 10/10/2022 |
| 0.0.5 | 817 | 10/10/2022 |
| 0.0.4 | 1,839 | 10/3/2022 |
| 0.0.3 | 2,859 | 9/23/2022 |
| 0.0.2 | 2,631 | 9/19/2022 |
| 0.0.1 | 583 | 9/19/2022 |