diff --git a/src/ZB.MOM.WW.ScadaBridge.Host/SiteServiceRegistration.cs b/src/ZB.MOM.WW.ScadaBridge.Host/SiteServiceRegistration.cs index 70cfec10..367a55ca 100644 --- a/src/ZB.MOM.WW.ScadaBridge.Host/SiteServiceRegistration.cs +++ b/src/ZB.MOM.WW.ScadaBridge.Host/SiteServiceRegistration.cs @@ -96,6 +96,19 @@ public static class SiteServiceRegistration return new AkkaClusterNodeProvider(akkaService, siteRole); }); + // SiteEventLogging-019 / #29 (M2.15): the EventLogPurgeService runs on every + // site host node but consults this optional gate each tick and early-exits on + // the standby. Register it to delegate to IClusterNodeProvider.SelfIsPrimary + // (the canonical "this node is Up AND cluster leader" check) so purge runs ONLY + // on the active node — no duplicated cluster logic. Non-clustered test hosts that + // never call SiteServiceRegistration leave it unregistered, so the purge defaults + // to always-run (the pre-fix behaviour, preserved). + services.AddSingleton(sp => + { + var nodeProvider = sp.GetRequiredService(); + return () => nodeProvider.SelfIsPrimary; + }); + // Options binding BindSharedOptions(services, config); services.Configure(config.GetSection("ScadaBridge:SiteRuntime")); diff --git a/tests/ZB.MOM.WW.ScadaBridge.Host.Tests/CompositionRootTests.cs b/tests/ZB.MOM.WW.ScadaBridge.Host.Tests/CompositionRootTests.cs index 15750328..ba94e831 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.Host.Tests/CompositionRootTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.Host.Tests/CompositionRootTests.cs @@ -405,6 +405,9 @@ public class SiteCompositionRootTests : IDisposable new object[] { typeof(IEventLogQueryService) }, new object[] { typeof(ISiteIdentityProvider) }, new object[] { typeof(IHealthReportTransport) }, + // M2.15 (#29): the active-node purge gate must be registered on site nodes + // so EventLogPurge only runs on the active node. + new object[] { typeof(SiteEventLogActiveNodeCheck) }, }; // --- Scoped services ---