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 }