ManagedCode.TimeSeries.Orleans 10.0.0

Prefix Reserved
dotnet add package ManagedCode.TimeSeries.Orleans --version 10.0.0
                    
NuGet\Install-Package ManagedCode.TimeSeries.Orleans -Version 10.0.0
                    
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.Orleans" Version="10.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ManagedCode.TimeSeries.Orleans" Version="10.0.0" />
                    
Directory.Packages.props
<PackageReference Include="ManagedCode.TimeSeries.Orleans" />
                    
Project file
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.Orleans --version 10.0.0
                    
#r "nuget: ManagedCode.TimeSeries.Orleans, 10.0.0"
                    
#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.Orleans@10.0.0
                    
#: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.Orleans&version=10.0.0
                    
Install as a Cake Addin
#tool nuget:?package=ManagedCode.TimeSeries.Orleans&version=10.0.0
                    
Install as a Cake Tool

ManagedCode TimeSeries

ManagedCode.TimeSeries

.NET Coverage Status Release CodeQL

Lock-free, allocation-conscious, thread-safe time-series primitives for building fast counters, rolling analytics, and metric pipelines in .NET 10 / C# 14.

Package NuGet
Core library NuGet Package

What is this library?

ManagedCode.TimeSeries is a high-performance .NET time series metrics library. It provides optimized, time-bucketed collections to aggregate events into time series:

  • Accumulators store raw events per time bucket (queue per bucket).
  • Summers store aggregated values per time bucket (sum/min/max/replace).
  • Groups manage many series by key (per endpoint, per customer, per shard, etc.).

It's designed for high-throughput analytics: clicks, tokens, CPU usage, money, events, and any numeric telemetry.

Why use it?

  • Lock-free ingestion for high write rates.
  • Thread-safe reads/writes for multi-threaded pipelines.
  • UTC-normalized timestamps for deterministic ordering.
  • Grouped series for multi-tenant metrics.
  • Orleans-friendly converters and System.Text.Json helpers.

Common use cases

  • Web analytics (page views, clicks, conversion funnels).
  • Infrastructure metrics (CPU, memory, latency, tokens).
  • Billing counters (money, usage, events per window).

Concepts (quick mental model)

  • SampleInterval: bucket size (e.g., 1s, 10s, 1m).
  • Samples/Buckets: ordered view of buckets keyed by UTC timestamps (Buckets is an alias of Samples).
  • MaxSamplesCount: maximum bucket count per series; 0 means unbounded (this is not the event count).
  • DataCount: total events processed (not the number of buckets).
  • UTC normalized: you can pass any DateTimeOffset, but values are normalized to UTC internally; offsets are not stored.
  • Thread-safe: concurrent reads/writes are supported across all public types.

Install

dotnet add package ManagedCode.TimeSeries

Quickstart

1) Make a rolling accumulator (store raw events)

using ManagedCode.TimeSeries.Accumulators;

var requests = new IntTimeSeriesAccumulator(
    sampleInterval: TimeSpan.FromSeconds(5),
    maxSamplesCount: 60); // 60 buckets -> 5 minutes at 5s interval

// Use current time (UTC internally)
requests.Record(1);
requests.Record(1);

Console.WriteLine($"Buckets: {requests.Samples.Count}");
Console.WriteLine($"Events: {requests.DataCount}");

2) Make a summer (store aggregates per bucket)

using ManagedCode.TimeSeries.Summers;
using ManagedCode.TimeSeries.Extensions;

var latency = new NumberTimeSeriesSummer<decimal>(TimeSpan.FromMilliseconds(500));

latency.Record(12.4m);
latency.Record(9.6m);

Console.WriteLine($"Sum: {latency.Sum()}");
Console.WriteLine($"Avg: {latency.Average():F2}");
Console.WriteLine($"Min/Max: {latency.Min()} / {latency.Max()}");

3) Track many keys at once (grouped series)

using ManagedCode.TimeSeries.Accumulators;
using ManagedCode.TimeSeries.Extensions;

var perEndpoint = new IntGroupTimeSeriesAccumulator(
    sampleInterval: TimeSpan.FromSeconds(1),
    maxSamplesCount: 300,
    deleteOverdueSamples: true);

perEndpoint.AddNewData("/home", 1);
perEndpoint.AddNewData("/checkout", 1);

foreach (var (endpoint, accumulator) in perEndpoint.Snapshot())
{
    Console.WriteLine($"{endpoint}: {accumulator.DataCount} hits");
}

4) Serialize/deserialize with System.Text.Json

using ManagedCode.TimeSeries.Accumulators;
using ManagedCode.TimeSeries.Serialization;

var series = new IntTimeSeriesAccumulator(TimeSpan.FromSeconds(1), maxSamplesCount: 10);
series.AddNewData(1);
series.AddNewData(2);

var json = TimeSeriesJsonSerializer.SerializeAccumulator<int, IntTimeSeriesAccumulator>(series);
var restored = TimeSeriesJsonSerializer.DeserializeAccumulator<int, IntTimeSeriesAccumulator>(json);

Console.WriteLine(restored.DataCount); // same as original

5) Orleans serialization (v9)

Converters in ManagedCode.TimeSeries.Orleans are marked with [RegisterConverter] and are auto-registered when the assembly is loaded. Reference the package from your silo and client projects so the converters are available. Converters are provided for int/float/double accumulators, summers, and grouped series, plus generic numeric summers.

Time handling (DateTimeOffset vs DateTime)

  • Public APIs accept DateTimeOffset so callers can pass any offset they have.
  • Internally, timestamps are normalized to UTC (offset zero) for speed and determinism.
  • If you need to preserve offsets, store them separately alongside your metric data.
  • If you do not need custom timestamps, use Record(value) or AddNewData(value) and let the library use DateTime.UtcNow.

Accumulators vs Summers

Type Stored per bucket Best for
Accumulator ConcurrentQueue<T> raw event lists, replay, exact values
Summer T (aggregated) fast stats, memory-efficient counters

Performance tips

  • Keep MaxSamplesCount reasonable to limit memory.
  • Use Record(value) (or AddNewData(value)) unless you must pass custom timestamps.
  • Use summers for high-volume metrics (they avoid storing every event).
  • Avoid locks in code that touches these structures.

Design notes

  • Accumulators use ConcurrentQueue<T> to remain lock-free and thread-safe under concurrent writes.
  • Even in single-threaded runtimes, timers and background cleanup can introduce concurrency.
  • If you need single-thread-only storage, consider using summers or ask for a dedicated single-thread accumulator.

Architecture

  • See docs/Architecture/Overview.md for detailed workflows, data model, and module boundaries.

Development Workflow

dotnet restore ManagedCode.TimeSeries.slnx
dotnet build ManagedCode.TimeSeries.slnx --configuration Release
dotnet format ManagedCode.TimeSeries.slnx
dotnet build ManagedCode.TimeSeries.slnx --configuration Release
dotnet test ManagedCode.TimeSeries.Tests/ManagedCode.TimeSeries.Tests.csproj --configuration Release

Extensibility

Scenario Hook
Custom numeric type Implement INumber<T> and use NumberTimeSeriesSummer<T>
Different aggregation Use Strategy or implement a custom summer
Serialization System.Text.Json helpers in ManagedCode.TimeSeries.Serialization

Contributing

  1. Restore/build/test using the commands above.
  2. Keep new APIs covered with tests (see existing samples in ManagedCode.TimeSeries.Tests).
  3. Keep hot paths lock-free; only introduce locking when unavoidable and document the trade-off.
  4. Update this README if you change behavior or public APIs.

License

MIT (c) ManagedCode SAS.

Product 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.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
10.0.0 81 1/11/2026
0.0.20 229 10/19/2025
0.0.18 340 5/17/2023