using System; using System.Collections.Generic; namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Host.Stability; /// /// Galaxy-specific RSS watchdog per driver-stability.md §"Memory Watchdog Thresholds". /// Baseline-relative + absolute caps. Sustained-slope detection uses a rolling 30-min window. /// Pluggable RSS source keeps it unit-testable. /// public sealed class MemoryWatchdog { /// Absolute hard ceiling — process is force-killed above this. public long HardCeilingBytes { get; init; } = 1_500L * 1024 * 1024; /// Sustained slope (bytes/min) above which soft recycle is scheduled. public long SustainedSlopeBytesPerMinute { get; init; } = 5L * 1024 * 1024; public TimeSpan SlopeWindow { get; init; } = TimeSpan.FromMinutes(30); private readonly long _baselineBytes; private readonly Queue _samples = new(); public MemoryWatchdog(long baselineBytes) { _baselineBytes = baselineBytes; } /// Called every 30s with the current RSS. Returns the action the supervisor should take. public WatchdogAction Sample(long rssBytes, DateTime utcNow) { _samples.Enqueue(new RssSample(utcNow, rssBytes)); while (_samples.Count > 0 && utcNow - _samples.Peek().TimestampUtc > SlopeWindow) _samples.Dequeue(); if (rssBytes >= HardCeilingBytes) return WatchdogAction.HardKill; var softThreshold = Math.Max(_baselineBytes * 2, _baselineBytes + 200L * 1024 * 1024); var warnThreshold = Math.Max((long)(_baselineBytes * 1.5), _baselineBytes + 200L * 1024 * 1024); if (rssBytes >= softThreshold) return WatchdogAction.SoftRecycle; if (rssBytes >= warnThreshold) return WatchdogAction.Warn; if (_samples.Count >= 2) { var oldest = _samples.Peek(); var span = (utcNow - oldest.TimestampUtc).TotalMinutes; if (span >= SlopeWindow.TotalMinutes * 0.9) // need ~full window to trust the slope { var delta = rssBytes - oldest.RssBytes; var bytesPerMin = delta / span; if (bytesPerMin >= SustainedSlopeBytesPerMinute) return WatchdogAction.SoftRecycle; } } return WatchdogAction.None; } private readonly record struct RssSample(DateTime TimestampUtc, long RssBytes); } public enum WatchdogAction { None, Warn, SoftRecycle, HardKill }