save checkpoint

This commit is contained in:
master
2026-02-11 01:32:14 +02:00
parent 5593212b41
commit cf5b72974f
2316 changed files with 68799 additions and 3808 deletions

View File

@@ -3,7 +3,10 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Npgsql;
using StellaOps.HybridLogicalClock;
using StellaOps.Eventing.Signing;
using StellaOps.Eventing.Storage;
using StellaOps.Eventing.Telemetry;
@@ -42,12 +45,26 @@ public static class ServiceCollectionExtensions
// Register event store based on configuration
var options = configuration.GetSection(EventingOptions.SectionName).Get<EventingOptions>();
TryAddHybridLogicalClock(services, options?.ServiceName);
if (options?.UseInMemoryStore == true)
{
services.TryAddSingleton<ITimelineEventStore, InMemoryTimelineEventStore>();
}
else
{
services.TryAddSingleton(sp =>
{
var configuredOptions = sp.GetRequiredService<IOptions<EventingOptions>>().Value;
if (string.IsNullOrWhiteSpace(configuredOptions.ConnectionString))
{
throw new InvalidOperationException(
"Eventing:ConnectionString must be configured when Eventing:UseInMemoryStore is false.");
}
return NpgsqlDataSource.Create(configuredOptions.ConnectionString);
});
services.TryAddSingleton<ITimelineEventStore, PostgresTimelineEventStore>();
}
@@ -84,6 +101,7 @@ public static class ServiceCollectionExtensions
.ValidateOnStart();
services.TryAddSingleton(TimeProvider.System);
TryAddHybridLogicalClock(services, serviceName);
// Register NpgsqlDataSource
services.TryAddSingleton(_ => NpgsqlDataSource.Create(connectionString));
@@ -119,6 +137,7 @@ public static class ServiceCollectionExtensions
.ValidateOnStart();
services.TryAddSingleton(TimeProvider.System);
TryAddHybridLogicalClock(services, serviceName);
services.TryAddSingleton<ITimelineEventStore, InMemoryTimelineEventStore>();
services.TryAddSingleton<ITimelineEventEmitter, TimelineEventEmitter>();
services.TryAddSingleton<EventingTelemetry>();
@@ -138,4 +157,33 @@ public static class ServiceCollectionExtensions
services.TryAddSingleton<IEventSigner, TSigner>();
return services;
}
private static void TryAddHybridLogicalClock(IServiceCollection services, string? nodeId)
{
var resolvedNodeId = ResolveNodeId(nodeId);
services.TryAddSingleton<IHlcStateStore, InMemoryHlcStateStore>();
services.TryAddSingleton<IHybridLogicalClock>(sp =>
{
var timeProvider = sp.GetRequiredService<TimeProvider>();
var stateStore = sp.GetRequiredService<IHlcStateStore>();
var logger = sp.GetRequiredService<ILogger<StellaOps.HybridLogicalClock.HybridLogicalClock>>();
return new StellaOps.HybridLogicalClock.HybridLogicalClock(
timeProvider,
resolvedNodeId,
stateStore,
logger);
});
}
private static string ResolveNodeId(string? nodeId)
{
if (string.IsNullOrWhiteSpace(nodeId))
{
return "eventing";
}
return nodeId.Trim().Replace(' ', '-').ToLowerInvariant();
}
}

View File

@@ -0,0 +1,59 @@
using FluentAssertions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using StellaOps.Eventing.Storage;
using StellaOps.HybridLogicalClock;
using Xunit;
namespace StellaOps.Eventing.Tests;
[Trait("Category", "Unit")]
public sealed class ServiceCollectionExtensionsTests
{
[Fact]
public void AddStellaOpsEventing_InMemoryStore_RegistersEmitterAndClock()
{
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>
{
["Eventing:ServiceName"] = "TimelineTests",
["Eventing:UseInMemoryStore"] = "true",
})
.Build();
var services = new ServiceCollection();
services.AddLogging();
services.AddStellaOpsEventing(configuration);
using var provider = services.BuildServiceProvider();
provider.GetRequiredService<IHybridLogicalClock>().Should().NotBeNull();
provider.GetRequiredService<ITimelineEventStore>().Should().BeOfType<InMemoryTimelineEventStore>();
provider.GetRequiredService<ITimelineEventEmitter>().Should().NotBeNull();
}
[Fact]
public void AddStellaOpsEventing_PostgresStore_RegistersEmitterClockAndStore()
{
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>
{
["Eventing:ServiceName"] = "TimelineTests",
["Eventing:UseInMemoryStore"] = "false",
["Eventing:ConnectionString"] = "Host=localhost;Port=5432;Database=timeline;Username=postgres;Password=postgres",
})
.Build();
var services = new ServiceCollection();
services.AddLogging();
services.AddStellaOpsEventing(configuration);
using var provider = services.BuildServiceProvider();
provider.GetRequiredService<IHybridLogicalClock>().Should().NotBeNull();
provider.GetRequiredService<ITimelineEventStore>().Should().BeOfType<PostgresTimelineEventStore>();
provider.GetRequiredService<ITimelineEventEmitter>().Should().NotBeNull();
}
}