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:
@@ -48,17 +48,26 @@ namespace ScadaLink.AuditLog.Site.Telemetry;
|
||||
public sealed class CachedCallTelemetryForwarder : ICachedCallTelemetryForwarder
|
||||
{
|
||||
private readonly IAuditWriter _auditWriter;
|
||||
private readonly IOperationTrackingStore _trackingStore;
|
||||
private readonly IOperationTrackingStore? _trackingStore;
|
||||
private readonly ILogger<CachedCallTelemetryForwarder> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Construct the forwarder. <paramref name="trackingStore"/> is optional —
|
||||
/// when null only the audit half of the packet is emitted, which matches
|
||||
/// the M3 Bundle F composition-root contract on Central nodes: the
|
||||
/// AuditLog DI surface registers the forwarder unconditionally (mirroring
|
||||
/// the IAuditWriter chain) but the site-only tracking store has no central
|
||||
/// registration. Production site nodes wire both — the central lazy
|
||||
/// resolution is a no-op path kept symmetric with the M2 writer chain.
|
||||
/// </summary>
|
||||
public CachedCallTelemetryForwarder(
|
||||
IAuditWriter auditWriter,
|
||||
IOperationTrackingStore trackingStore,
|
||||
IOperationTrackingStore? trackingStore,
|
||||
ILogger<CachedCallTelemetryForwarder> logger)
|
||||
{
|
||||
_auditWriter = auditWriter ?? throw new ArgumentNullException(nameof(auditWriter));
|
||||
_trackingStore = trackingStore ?? throw new ArgumentNullException(nameof(trackingStore));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_trackingStore = trackingStore;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -100,6 +109,15 @@ public sealed class CachedCallTelemetryForwarder : ICachedCallTelemetryForwarder
|
||||
|
||||
private async Task TryEmitTrackingAsync(CachedCallTelemetry telemetry, CancellationToken ct)
|
||||
{
|
||||
if (_trackingStore is null)
|
||||
{
|
||||
// No site-local tracking store wired — Central composition root or
|
||||
// an integration-test host that skipped AddSiteRuntime. Emitting
|
||||
// through the audit half is still meaningful; the tracking half
|
||||
// is a no-op rather than an error.
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
switch (telemetry.Audit.Kind)
|
||||
|
||||
Reference in New Issue
Block a user