M3 Bundle F (Task F1) wires the cached-call audit pipeline through the composition roots: - Central: register SiteCallAuditActor as a cluster singleton + proxy (mirrors AuditLogIngestActor and NotificationOutboxActor). Program.cs calls .AddSiteCallAudit() on the central role. - Site: register ICachedCallTelemetryForwarder + CachedCallLifecycleBridge in AddAuditLog (lazy factory — Central nodes degrade to audit-only emission because IOperationTrackingStore is site-only). - Site: bind CachedCallLifecycleBridge to ICachedCallLifecycleObserver so StoreAndForwardService picks it up via DI. - Site: introduce IStoreAndForwardSiteContext + Host adapter to surface the site id to StoreAndForwardService without creating a StoreAndForward -> HealthMonitoring project-reference cycle. - ScriptExecutionActor resolves ICachedCallTelemetryForwarder per script scope and threads it into ScriptRuntimeContext. CachedCallTelemetryForwarder's IOperationTrackingStore dependency is now nullable so Central DI validation succeeds with the lazy registration; the forwarder's tracking-half emission is a no-op when the store is absent. Tests: - AkkaHostedServiceAuditWiringTests: Central host builds with AddSiteCallAudit and resolves ICachedCallTelemetryForwarder; Site resolves the forwarder + bridge + observer + IStoreAndForwardSiteContext. - Full solution: 194 Host tests green, 241 SiteRuntime tests green, every other suite unchanged.
This commit is contained in:
@@ -102,6 +102,33 @@ public static class ServiceCollectionExtensions
|
||||
// SiteAuditTelemetryActor's Props.Create call.
|
||||
services.AddSingleton<ISiteStreamAuditClient, NoOpSiteStreamAuditClient>();
|
||||
|
||||
// M3 Bundle F: site-side dual emitter for cached-call lifecycle
|
||||
// telemetry. ScriptRuntimeContext.ExternalSystem.CachedCall /
|
||||
// Database.CachedWrite resolves this through DI and pushes one combined
|
||||
// packet per lifecycle event; the forwarder writes the audit half
|
||||
// through IAuditWriter and the operational half through the
|
||||
// IOperationTrackingStore. The audit writer is always wired (the M2
|
||||
// chain above); the operational tracking store is SITE-ONLY (registered
|
||||
// by ScadaLink.SiteRuntime). On a Central composition root the tracking
|
||||
// store has no registration, so the factory resolves it with GetService
|
||||
// (returning null) — the forwarder degrades to "audit-only" emission,
|
||||
// mirroring the lazy IAuditWriter chain established in M2.
|
||||
services.AddSingleton<ICachedCallTelemetryForwarder>(sp =>
|
||||
new CachedCallTelemetryForwarder(
|
||||
sp.GetRequiredService<IAuditWriter>(),
|
||||
sp.GetService<ScadaLink.Commons.Interfaces.IOperationTrackingStore>(),
|
||||
sp.GetRequiredService<ILogger<CachedCallTelemetryForwarder>>()));
|
||||
|
||||
// M3 Bundle F: bridge the store-and-forward retry-loop observer hook
|
||||
// to the cached-call forwarder so per-attempt + terminal telemetry
|
||||
// emitted from the S&F retry sweep lands on the same SQLite hot-path
|
||||
// as the script-thread CachedSubmit row. Registered as a singleton
|
||||
// and also bound to ICachedCallLifecycleObserver so AddStoreAndForward
|
||||
// can resolve it through DI (Bundle F StoreAndForward wiring change).
|
||||
services.AddSingleton<CachedCallLifecycleBridge>();
|
||||
services.AddSingleton<ICachedCallLifecycleObserver>(
|
||||
sp => sp.GetRequiredService<CachedCallLifecycleBridge>());
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user