fix(communication)+fix(siteruntime): carry DetachedScriptThreads/ScriptRunShedCount/SiteStreamAlarmDropCount across the health wire; restore drained counters on failed send (arch-review 2026-08-19 P8-1)

This commit is contained in:
Joseph Doherty
2026-08-19 14:47:04 -04:00
parent eca0ab768d
commit d0a748e632
9 changed files with 228 additions and 45 deletions
@@ -132,7 +132,8 @@ public class CentralHealthReportLoop : BackgroundService
alarmErrors: report.AlarmEvaluationErrorCount,
deadLetters: report.DeadLetterCount,
siteAuditWriteFailures: report.SiteAuditWriteFailures,
auditRedactionFailures: report.AuditRedactionFailure);
auditRedactionFailures: report.AuditRedactionFailure,
scriptRunShedCount: report.ScriptRunShedCount);
throw;
}
@@ -182,7 +182,8 @@ public class HealthReportSender : BackgroundService
alarmErrors: report.AlarmEvaluationErrorCount,
deadLetters: report.DeadLetterCount,
siteAuditWriteFailures: report.SiteAuditWriteFailures,
auditRedactionFailures: report.AuditRedactionFailure);
auditRedactionFailures: report.AuditRedactionFailure,
scriptRunShedCount: report.ScriptRunShedCount);
throw;
}
@@ -286,12 +286,19 @@ public interface ISiteHealthCollector
/// <param name="deadLetters">Dead letter count to add back.</param>
/// <param name="siteAuditWriteFailures">Site audit write failure count to add back.</param>
/// <param name="auditRedactionFailures">Audit redaction failure count to add back.</param>
/// <param name="scriptRunShedCount">
/// Interval-drained script/alarm run-shed count to add back (arch-review 2026-08-19
/// P8-1). Additive trailing parameter defaulting to 0 so existing callers keep
/// compiling; <c>DetachedScriptThreads</c>/<c>SiteStreamAlarmDropCount</c> are
/// point-in-time gauges, not drained on collect, so they need no restore path.
/// </param>
void AddIntervalCounters(
int scriptErrors,
int alarmErrors,
int deadLetters,
int siteAuditWriteFailures,
int auditRedactionFailures)
int auditRedactionFailures,
int scriptRunShedCount = 0)
{
// Default no-op so test fakes do not need to be updated. The real
// SiteHealthCollector overrides this with the Interlocked.Add restore.
@@ -245,19 +245,25 @@ public class SiteHealthCollector : ISiteHealthCollector
int alarmErrors,
int deadLetters,
int siteAuditWriteFailures,
int auditRedactionFailures)
int auditRedactionFailures,
int scriptRunShedCount = 0)
{
// Each counter is restored atomically via
// Interlocked.Add so an increment that arrived during the failed Send
// (and therefore accumulated against the zero left by CollectReport's
// Exchange) is correctly summed with the values being put back. No
// ordering between the five Adds is required — they target independent
// fields.
// ordering between the six Adds is required — they target independent
// fields. scriptRunShedCount joins this restore path (arch-review
// 2026-08-19 P8-1) because it is drained by CollectReport the same way
// as the other five; DetachedScriptThreads and SiteStreamAlarmDropCount
// are point-in-time gauges (CompareExchange/Read, never zeroed on
// collect) so a failed Send loses nothing for them to restore.
if (scriptErrors != 0) Interlocked.Add(ref _scriptErrorCount, scriptErrors);
if (alarmErrors != 0) Interlocked.Add(ref _alarmErrorCount, alarmErrors);
if (deadLetters != 0) Interlocked.Add(ref _deadLetterCount, deadLetters);
if (siteAuditWriteFailures != 0) Interlocked.Add(ref _siteAuditWriteFailures, siteAuditWriteFailures);
if (auditRedactionFailures != 0) Interlocked.Add(ref _auditRedactionFailures, auditRedactionFailures);
if (scriptRunShedCount != 0) Interlocked.Add(ref _scriptRunShedCount, scriptRunShedCount);
}
/// <inheritdoc />