namespace MoShiro.Agent; /// Reconnect cadence for the control connection of a single dialer-to-listener path: 1, 2, 4, 8, 16, then five 32-second waits, then once per minute. public sealed class ControlBackoff { private static readonly TimeSpan[] s_delays = [ TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(4), TimeSpan.FromSeconds(8), TimeSpan.FromSeconds(16), TimeSpan.FromSeconds(32), TimeSpan.FromSeconds(32), TimeSpan.FromSeconds(32), TimeSpan.FromSeconds(32), TimeSpan.FromSeconds(32), ]; private const int MaxMinutes = 10; private int _attempt; public int Attempts => Volatile.Read(ref _attempt); public TimeSpan Next() { int attempt = Interlocked.Increment(ref _attempt) - 1; if (attempt < s_delays.Length) { return s_delays[attempt]; } // 表走完还连不上(对端关了、这台机器没有这条路由):一分钟起继续翻倍,最长十分钟,不再每分钟白白重试一次、写三条日志 return TimeSpan.FromMinutes(Math.Min(MaxMinutes, 1 << Math.Min(attempt - s_delays.Length, 4))); } public void Reset() => Interlocked.Exchange(ref _attempt, 0); }