feat(audit): start purge + reconciliation singletons; production ISiteEnumerator
This commit is contained in:
@@ -588,6 +588,117 @@ akka {{
|
||||
_logger.LogInformation(
|
||||
"SiteCallAuditActor singleton created and registered with CentralCommunicationActor");
|
||||
|
||||
// Audit Log (#23) M6 Bundle B/C — start the two central-only maintenance
|
||||
// singletons that were fully implemented but never instantiated: the
|
||||
// daily AuditLog partition-switch purge (AuditLogPurgeActor) and the
|
||||
// periodic per-site audit-event reconciliation pull
|
||||
// (SiteAuditReconciliationActor). Both mirror the SiteCallAudit /
|
||||
// NotificationOutbox singleton pattern above: a ClusterSingletonManager
|
||||
// pins the actor to the active central node, a ClusterSingletonProxy
|
||||
// gives a stable address, and a PhaseClusterLeave graceful-stop task
|
||||
// drains the in-flight tick before handover. Options + the production
|
||||
// ISiteEnumerator + IPullAuditEventsClient come from
|
||||
// AddAuditLogCentralReconciliationClient (central composition root only).
|
||||
// Both actors take the root IServiceProvider and open their own per-tick
|
||||
// DI scope because IAuditLogRepository / ISiteRepository are scoped EF
|
||||
// Core services.
|
||||
var auditPurgeLogger = _serviceProvider.GetRequiredService<ILoggerFactory>()
|
||||
.CreateLogger<ZB.MOM.WW.ScadaBridge.AuditLog.Central.AuditLogPurgeActor>();
|
||||
var auditPurgeOptions = _serviceProvider
|
||||
.GetRequiredService<IOptions<ZB.MOM.WW.ScadaBridge.AuditLog.Central.AuditLogPurgeOptions>>();
|
||||
var auditLogOptions = _serviceProvider
|
||||
.GetRequiredService<IOptions<ZB.MOM.WW.ScadaBridge.AuditLog.Configuration.AuditLogOptions>>();
|
||||
|
||||
var auditPurgeSingletonProps = ClusterSingletonManager.Props(
|
||||
singletonProps: Props.Create(() => new ZB.MOM.WW.ScadaBridge.AuditLog.Central.AuditLogPurgeActor(
|
||||
_serviceProvider,
|
||||
auditPurgeOptions,
|
||||
auditLogOptions,
|
||||
auditPurgeLogger)),
|
||||
terminationMessage: PoisonPill.Instance,
|
||||
settings: ClusterSingletonManagerSettings.Create(_actorSystem!)
|
||||
.WithSingletonName("audit-log-purge"));
|
||||
var auditPurgeSingletonManager =
|
||||
_actorSystem!.ActorOf(auditPurgeSingletonProps, "audit-log-purge-singleton");
|
||||
|
||||
var auditPurgeShutdown = Akka.Actor.CoordinatedShutdown.Get(_actorSystem);
|
||||
auditPurgeShutdown.AddTask(
|
||||
Akka.Actor.CoordinatedShutdown.PhaseClusterLeave,
|
||||
"drain-audit-log-purge-singleton",
|
||||
async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await auditPurgeSingletonManager.GracefulStop(TimeSpan.FromSeconds(10));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex,
|
||||
"AuditLogPurge singleton did not drain within the graceful-stop "
|
||||
+ "timeout; falling through to PoisonPill handover");
|
||||
}
|
||||
return Akka.Done.Instance;
|
||||
});
|
||||
|
||||
var auditPurgeProxyProps = ClusterSingletonProxy.Props(
|
||||
singletonManagerPath: "/user/audit-log-purge-singleton",
|
||||
settings: ClusterSingletonProxySettings.Create(_actorSystem)
|
||||
.WithSingletonName("audit-log-purge"));
|
||||
_actorSystem.ActorOf(auditPurgeProxyProps, "audit-log-purge-proxy");
|
||||
_logger.LogInformation("AuditLogPurgeActor singleton created");
|
||||
|
||||
// SiteAuditReconciliationActor — self-healing fallback puller. Resolves
|
||||
// its production ISiteEnumerator (config-DB Site projection) and
|
||||
// IPullAuditEventsClient (gRPC) from the central reconciliation-client
|
||||
// helper registered in Program.cs.
|
||||
var auditReconLogger = _serviceProvider.GetRequiredService<ILoggerFactory>()
|
||||
.CreateLogger<ZB.MOM.WW.ScadaBridge.AuditLog.Central.SiteAuditReconciliationActor>();
|
||||
var auditReconOptions = _serviceProvider
|
||||
.GetRequiredService<IOptions<ZB.MOM.WW.ScadaBridge.AuditLog.Central.SiteAuditReconciliationOptions>>();
|
||||
var auditReconSites = _serviceProvider
|
||||
.GetRequiredService<ZB.MOM.WW.ScadaBridge.AuditLog.Central.ISiteEnumerator>();
|
||||
var auditReconClient = _serviceProvider
|
||||
.GetRequiredService<ZB.MOM.WW.ScadaBridge.AuditLog.Central.IPullAuditEventsClient>();
|
||||
|
||||
var auditReconSingletonProps = ClusterSingletonManager.Props(
|
||||
singletonProps: Props.Create(() => new ZB.MOM.WW.ScadaBridge.AuditLog.Central.SiteAuditReconciliationActor(
|
||||
auditReconSites,
|
||||
auditReconClient,
|
||||
_serviceProvider,
|
||||
auditReconOptions,
|
||||
auditReconLogger)),
|
||||
terminationMessage: PoisonPill.Instance,
|
||||
settings: ClusterSingletonManagerSettings.Create(_actorSystem!)
|
||||
.WithSingletonName("site-audit-reconciliation"));
|
||||
var auditReconSingletonManager =
|
||||
_actorSystem!.ActorOf(auditReconSingletonProps, "site-audit-reconciliation-singleton");
|
||||
|
||||
var auditReconShutdown = Akka.Actor.CoordinatedShutdown.Get(_actorSystem);
|
||||
auditReconShutdown.AddTask(
|
||||
Akka.Actor.CoordinatedShutdown.PhaseClusterLeave,
|
||||
"drain-site-audit-reconciliation-singleton",
|
||||
async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await auditReconSingletonManager.GracefulStop(TimeSpan.FromSeconds(10));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex,
|
||||
"SiteAuditReconciliation singleton did not drain within the graceful-stop "
|
||||
+ "timeout; falling through to PoisonPill handover");
|
||||
}
|
||||
return Akka.Done.Instance;
|
||||
});
|
||||
|
||||
var auditReconProxyProps = ClusterSingletonProxy.Props(
|
||||
singletonManagerPath: "/user/site-audit-reconciliation-singleton",
|
||||
settings: ClusterSingletonProxySettings.Create(_actorSystem)
|
||||
.WithSingletonName("site-audit-reconciliation"));
|
||||
_actorSystem.ActorOf(auditReconProxyProps, "site-audit-reconciliation-proxy");
|
||||
_logger.LogInformation("SiteAuditReconciliationActor singleton created");
|
||||
|
||||
_logger.LogInformation("Central actors registered. CentralCommunicationActor created.");
|
||||
}
|
||||
|
||||
|
||||
@@ -97,6 +97,13 @@ try
|
||||
// pf_AuditLog_Month forward monthly. Depends on IPartitionMaintenance
|
||||
// (registered below by AddConfigurationDatabase).
|
||||
builder.Services.AddAuditLogCentralMaintenance(builder.Configuration);
|
||||
// #23 M6 Bundle B/C — central-only registration backing the two
|
||||
// maintenance singletons started in AkkaHostedService: the production
|
||||
// ISiteEnumerator + IPullAuditEventsClient (gRPC) used by the
|
||||
// SiteAuditReconciliationActor, plus the AuditLogPurgeOptions /
|
||||
// SiteAuditReconciliationOptions bindings consumed by both singletons.
|
||||
// Central-only by design (it dials sites), kept out of AddAuditLog.
|
||||
builder.Services.AddAuditLogCentralReconciliationClient(builder.Configuration);
|
||||
// Site Call Audit (#22) — central node owns the SiteCallAuditActor
|
||||
// singleton (M3 Bundle F). The extension itself currently registers
|
||||
// nothing — actor Props are constructed inline in AkkaHostedService —
|
||||
|
||||
Reference in New Issue
Block a user