The control layer keeps doubling after the first minute up to ten minutes, and the QUIC redial doubles after twelve short attempts up to five minutes, instead of retrying every minute or every five seconds forever.
32 lines
1.2 KiB
C#
32 lines
1.2 KiB
C#
namespace MoShiro.Agent;
|
|
|
|
/// <summary>
|
|
/// QUIC 数据通道的重拨节奏:1、2、3、5 秒,之后固定 5 秒。数据通道断开期间的测量是缺口,所以不像控制连接那样拉长到一分钟。
|
|
/// 抖动由调用方通过 <paramref name="random"/> 给出,避免多条线路同时重拨。
|
|
/// </summary>
|
|
public sealed class QuicRedialBackoff
|
|
{
|
|
private static readonly TimeSpan[] s_delays = [TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(5)];
|
|
|
|
private const int ShortAttempts = 12;
|
|
|
|
private int _attempt;
|
|
|
|
public int Attempts => _attempt;
|
|
|
|
public TimeSpan Next(Random? random = null)
|
|
{
|
|
TimeSpan delay = s_delays[Math.Min(_attempt, s_delays.Length - 1)];
|
|
if (_attempt >= ShortAttempts)
|
|
{
|
|
// 短间隔已经连续失败了这么多次:这条路径大概率是死的(对端不通、被丢弃),握手和日志都是白费,翻倍退避,最长五分钟
|
|
delay = TimeSpan.FromSeconds(Math.Min(300, 5 * (1 << Math.Min(_attempt - ShortAttempts + 1, 6))));
|
|
}
|
|
|
|
_attempt++;
|
|
return random is null ? delay : delay * (0.8 + (0.4 * random.NextDouble()));
|
|
}
|
|
|
|
public void Reset() => _attempt = 0;
|
|
}
|