feat(localdb): gRPC sync adapters, background service, replication DI
Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
This commit is contained in:
+54
@@ -0,0 +1,54 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ZB.MOM.WW.LocalDb.Replication;
|
||||
|
||||
/// <summary>DI + endpoint wiring for the 2-node gRPC replication engine.</summary>
|
||||
public static class ReplicationServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Binds and validates <see cref="ReplicationOptions"/> from the <c>"LocalDb:Replication"</c>
|
||||
/// configuration section, registers the passive <see cref="LocalDbSyncService"/> as a singleton
|
||||
/// (its single-stream guard must span calls), and registers the initiating
|
||||
/// <see cref="SyncBackgroundService"/> as a hosted service ONLY when a peer address is configured
|
||||
/// (a passive node leaves it empty and never dials). Idempotent. Requires
|
||||
/// <see cref="LocalDbServiceCollectionExtensions.AddZbLocalDb"/> to have been called for the
|
||||
/// <see cref="ILocalDb"/> the adapters depend on.
|
||||
/// </summary>
|
||||
public static IServiceCollection AddZbLocalDbReplication(
|
||||
this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
// Idempotent: a second call must not re-bind options or double-register the service/host.
|
||||
if (services.Any(d => d.ServiceType == typeof(LocalDbSyncService)))
|
||||
return services;
|
||||
|
||||
services.AddOptions<ReplicationOptions>()
|
||||
.Bind(configuration.GetSection("LocalDb:Replication"))
|
||||
.ValidateOnStart();
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Singleton<IValidateOptions<ReplicationOptions>, ReplicationOptionsValidator>());
|
||||
|
||||
services.AddSingleton<LocalDbSyncService>();
|
||||
|
||||
// Read the section directly (before options are built) to decide whether this node initiates.
|
||||
var peerAddress = configuration.GetSection("LocalDb:Replication")["PeerAddress"];
|
||||
if (!string.IsNullOrEmpty(peerAddress))
|
||||
services.AddHostedService<SyncBackgroundService>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps the passive <see cref="LocalDbSyncService"/> gRPC endpoint. The host must have called
|
||||
/// <c>AddGrpc()</c> and set up routing.
|
||||
/// </summary>
|
||||
public static IEndpointRouteBuilder MapZbLocalDbSync(this IEndpointRouteBuilder endpoints)
|
||||
{
|
||||
endpoints.MapGrpcService<LocalDbSyncService>();
|
||||
return endpoints;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user