feat(localdb): telemetry meters + ISyncStatus

Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
This commit is contained in:
Joseph Doherty
2026-07-18 00:03:39 -04:00
parent 8befebd476
commit be4ca76f5f
9 changed files with 765 additions and 8 deletions
@@ -4,6 +4,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using ZB.MOM.WW.LocalDb.Replication.Internal;
namespace ZB.MOM.WW.LocalDb.Replication;
@@ -32,6 +33,30 @@ public static class ReplicationServiceCollectionExtensions
services.TryAddEnumerable(
ServiceDescriptor.Singleton<IValidateOptions<ReplicationOptions>, ReplicationOptionsValidator>());
// Telemetry is optional but always registered here; the sessions/adapters hold nullable
// references and null-guard every call, so a consumer that never collects metrics is
// unaffected. The oplog-depth / lag / backlog observers poll a cheap synchronous store SELECT.
services.TryAddSingleton<SyncStatus>(sp =>
{
var db = SyncSessionFactory.RequireSqlite(sp.GetRequiredService<ILocalDb>(), nameof(SyncStatus));
var options = sp.GetRequiredService<IOptions<ReplicationOptions>>().Value;
var store = new OplogStore(db, options);
return new SyncStatus { OplogBacklogProvider = store.GetOplogDepthSync };
});
services.TryAddSingleton<ISyncStatus>(sp => sp.GetRequiredService<SyncStatus>());
services.TryAddSingleton<LocalDbMetrics>(sp =>
{
var db = SyncSessionFactory.RequireSqlite(sp.GetRequiredService<ILocalDb>(), nameof(LocalDbMetrics));
var options = sp.GetRequiredService<IOptions<ReplicationOptions>>().Value;
var store = new OplogStore(db, options);
var status = sp.GetRequiredService<SyncStatus>();
return new LocalDbMetrics
{
OplogDepthProvider = store.GetOplogDepthSync,
LastSyncUtcProvider = () => status.LastSyncUtc,
};
});
services.AddSingleton<LocalDbSyncService>();
services.AddHostedService<SyncBackgroundService>();