LockFree.EventStore 1.0.5

There is a newer version of this package available.
See the version list below for details.
dotnet add package LockFree.EventStore --version 1.0.5
                    
NuGet\Install-Package LockFree.EventStore -Version 1.0.5
                    
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="LockFree.EventStore" Version="1.0.5" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="LockFree.EventStore" Version="1.0.5" />
                    
Directory.Packages.props
<PackageReference Include="LockFree.EventStore" />
                    
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 LockFree.EventStore --version 1.0.5
                    
#r "nuget: LockFree.EventStore, 1.0.5"
                    
#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 LockFree.EventStore@1.0.5
                    
#: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=LockFree.EventStore&version=1.0.5
                    
Install as a Cake Addin
#tool nuget:?package=LockFree.EventStore&version=1.0.5
                    
Install as a Cake Tool

<img src="https://raw.githubusercontent.com/daniloneto/lockfree-eventstore/refs/heads/main/lockfreeeventstore.png" />

CI NuGet

Um banco de eventos em memória, rodando como serviço, para sincronizar e validar operações entre múltiplas instâncias com alta concorrência e sem travas.


🚀 Comece em 3 passos

1. Suba o servidor

docker run --rm -p 7070:7070 daniloneto/lockfree-eventstore:latest

2. Adicione o cliente

dotnet add package LockFree.EventStore

3. Escreva e leia

var es = new EventStoreClient("http://localhost:7070");
await es.Append("gateway/orders", new OrderCreated { Id = "o-1", Valor = 123 });
await foreach (var ev in es.Read("gateway/orders", from: 0))
{
    /* tratar evento */
}

🔁 Sample de Cliente

Veja samples/ClientSample para um exemplo que:

  • Envia eventos em paralelo para gateway/orders
  • Lê os eventos de volta
  • Calcula agregações locais

Para executar:

docker run --rm -p 7070:7070 daniloneto/lockfree-eventstore:latest
cd samples/ClientSample
 dotnet run

🌐 Exemplo com múltiplos Gateways (docker-compose)

Subir 1 EventStore, 3 gateways e Nginx balanceando:

docker compose up --build

Testar envio de pedidos (balanceado entre gateways):

curl -X POST http://localhost:8080/orders
curl -X POST 'http://localhost:8080/orders/bulk?n=50'

Ver estatísticas:

curl http://localhost:8080/stats/local    # stats de um gateway (um dos 3)
curl http://localhost:8080/stats/global   # consolidação global (via leitura central)

💡 Por que usar

  • Concorrência real: múltiplos gravadores sem mutex.
  • Integridade garantida: ordenação consistente, append condicional e idempotência.
  • Operação simples: sem coordenação externa, sem dependências.

📌 Cenário típico

Dois (ou mais) gateways atrás de um balanceador de carga precisam registrar operações no mesmo stream.
O Lockfree.EventStore garante ordem e integridade mesmo sob alto paralelismo, sem depender de locks, mantendo todo o estado em memória.


📚 Documentação completa

A seguir, a documentação técnica completa da API, recursos avançados, benchmarks e exemplos de uso.

Principais Recursos

  • Escrita MPMC lock-free com descarte FIFO
  • Particionamento por chave para alta concorrência
  • Snapshots consistentes sem bloquear produtores
  • Agregações funcionais e consultas por janela temporal
  • Zero dependências externas, pronto para AOT/Trimming
  • API fluente para configuração avançada
  • Métricas e observabilidade integradas
  • Agregações especializadas (Soma, Média, Mínimo, Máximo)

Exemplo de Uso Básico

var store = new EventStore<Pedido>();
store.TryAppend(new Pedido { Id = 1, Valor = 10m, Timestamp = DateTime.UtcNow });

var total = store.Aggregate(() => 0m, (acc, e) => acc + e.Valor,
    from: DateTime.UtcNow.AddMinutes(-10));

Novos Construtores

// Capacidade explícita
var store = new EventStore<Pedido>(capacidade: 100_000);

// Capacidade e partições
var store = new EventStore<Pedido>(capacidade: 50_000, particoes: 8);

// Configuração avançada
var store = new EventStore<Pedido>(new EventStoreOptions<Pedido>
{
    Capacidade = 100_000,
    Particoes = 16,
    OnEventDiscarded = evt => Logger.LogTrace("Evento descartado: {Event}", evt),
    OnCapacityReached = () => Metrics.IncrementCounter("eventstore.capacidade_atingida"),
    TimestampSelector = new PedidoTimestampSelector()
});

// API fluente
var store = EventStore.For<Pedido>()
    .WithCapacity(100_000)
    .WithPartitions(8)
    .OnDiscarded(evt => Log(evt))
    .OnCapacityReached(() => NotificarAdmin())
    .WithTimestampSelector(new PedidoTimestampSelector())
    .Create();

Propriedades de Estado

store.Count          // Número atual de eventos
store.Capacity       // Capacidade máxima configurada
store.IsEmpty        // Se está vazio
store.IsFull         // Se atingiu capacidade máxima
store.Partitions     // Número de partições

Agregações Especializadas

// Contagem por janela temporal
var count = store.Count(from: inicio, to: fim);

// Soma de valores
var sum = store.Sum(evt => evt.Valor, from: inicio, to: fim);

// Média
var avg = store.Average(evt => evt.Valor, from: inicio, to: fim);

// Mínimo e máximo
var min = store.Min(evt => evt.Pontuacao, from: inicio, to: fim);
var max = store.Max(evt => evt.Pontuacao, from: inicio, to: fim);

// Com filtros
var filteredSum = store.Sum(
    evt => evt.Valor, 
    filter: evt => evt.Tipo == "Pagamento",
    from: inicio, 
    to: fim
);

Snapshots com Filtros

// Snapshot filtrado
var eventosRecentes = store.Snapshot(
    filter: evt => evt.Timestamp > DateTime.UtcNow.AddMinutes(-5)
);

// Snapshot por janela temporal
var snapshot = store.Snapshot(from: inicio, to: fim);

// Snapshot com filtro e janela temporal
var filtrado = store.Snapshot(
    filter: evt => evt.Valor > 100,
    from: inicio,
    to: fim
);

Limpeza e Manutenção

// Limpar todos os eventos
store.Clear();
store.Reset(); // Alias para Clear()

// Purgar eventos antigos (requer TimestampSelector)
store.Purge(olderThan: DateTime.UtcNow.AddHours(-1));

Métricas e Observabilidade

// Estatísticas detalhadas
store.Statistics.TotalAppended        // Total de eventos adicionados
store.Statistics.TotalDiscarded       // Total de eventos descartados
store.Statistics.AppendsPerSecond     // Taxa atual de adições
store.Statistics.LastAppendTime       // Timestamp da última adição

Exemplos

MetricsDashboard

API web completa para coleta e consulta de métricas em tempo real:

cd .\samples\MetricsDashboarddotnet run

Endpoints disponíveis:

  • POST /metrics - Adicionar métrica
  • GET /metrics/sum?label=cpu_usage - Somar valores por label
  • GET /metrics/top?k=5 - Top K métricas

Veja samples/MetricsDashboard/TESTING.md para guia completo de testes.

API Completa

  • TryAppend(event) — Adiciona evento, lock-free
  • Aggregate — Agrega valores por janela temporal
  • Snapshot() — Retorna cópia imutável dos eventos
  • Count/Sum/Average/Min/Max — Agregações especializadas
  • Clear/Reset/Purge — Métodos de limpeza
  • Query — Consultas flexíveis com filtros
  • Statistics — Métricas para monitoramento

Partições

O número de partições padrão é Environment.ProcessorCount. É possível forçar a partição usando TryAppend(e, partition).

Snapshots

Snapshot() retorna uma cópia imutável aproximada do estado atual de todas as partições, ordenada do evento mais antigo para o mais novo por partição.

Performance

Projetado para alta concorrência e baixa latência. A ordem global entre partições é aproximada.


Benchmarks de Performance

Tipos por Valor vs Tipos por Referência

Operação Tipo Valor Tipo Referência Melhoria
Adição de Evento 560 ms 797 ms 42% mais rápido
Iteração de Eventos 35.8 ns 132.5 ns 74% mais rápido
Consultas de Eventos 393.5 ns 1,749.1 ns 77% mais rápido

Structure of Arrays (SoA) vs Array of Structures (AoS)

Operação SoA AoS Melhoria
Agregação por Chave 55.2 ms 74.6 ms 26% mais rápido
Uso de Memória Menor Maior Variável

Conclusões:

  1. Tipos por valor são significativamente mais rápidos que tipos por referência para leitura e escrita.
  2. SoA melhora cache locality e reduz pressão de memória.
  3. Para alto throughput, a implementação EventStoreV2 é recomendada.
// Usando EventStoreV2 com tipos por valor
var store = new EventStoreV2(capacidade: 1_000_000, particoes: 16);
store.Add("sensor1", 25.5, DateTime.UtcNow.Ticks);
double media = store.Average("sensor1");

Limitações

  • Ordem global apenas aproximada entre partições
  • Capacidade fixa; eventos antigos são descartados ao exceder

Licença

MIT

Product 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

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
1.0.11 13 8/27/2025
1.0.10 37 8/26/2025
1.0.9 40 8/26/2025
1.0.8 97 8/21/2025
1.0.7 102 8/20/2025
1.0.6 111 8/20/2025
1.0.5 121 8/10/2025
1.0.2 214 8/6/2025
1.0.0 151 8/4/2025
0.1.3 25 8/2/2025
0.1.2 94 8/1/2025
0.1.1 94 8/1/2025

v1.0.5: Endpoints genéricos de streams, agregação com durationMs, endpoints administrativos, samples GatewayClient & docker-compose + Nginx, scripts de cenário, Dockerfiles multi-stage, dependência Ulid.