feat: daily node restart controlled from the admin, connect timings as a default line task [CI]
ci/woodpecker/push/main-amd64-build Pipeline was successful

Agents and Probes exit in order at a configured time (default 04:30 UTC+8, switch and time zone in the admin settings) and the service manager starts them again; a local restart_at or MOSHIRO_RESTART_AT wins. The connect kind (TCP connect and TLS handshake timings) is now a default continuous line template, with a section on the line page.
This commit is contained in:
justme committed 2026-10-07 14:56:50 +08:00
1 parent 388619b8b6
commit 9bcef56497
37 files changed
+928 -101

No files matched your search

@@ -0,0 +1,73 @@
namespace Fleet.Hosting;
/// <summary>
/// 当前生效的定时重启:节点本地的设置优先;本地没有写时用面板下发的,面板改了之后立即重新排下一次,不需要重启进程。
/// </summary>
public sealed class RestartController : IDisposable
{
private readonly RestartSchedule? _local;
private readonly object _gate = new();
private RestartSchedule? _remote;
private CancellationTokenSource _changed = new();
public RestartController(RestartSchedule? local = null)
{
_local = local;
}
/// <summary>本地有设置时为 true:面板下发的不生效。</summary>
public bool IsLocal => _local is not null;
public RestartSchedule? Current
{
get
{
lock (_gate)
{
return _local ?? _remote;
}
}
}
/// <summary>当前设置被改动时会被取消的令牌;先取令牌、再取 <see cref="Current"/>,就不会漏掉中间的改动。</summary>
public CancellationToken ChangeToken
{
get
{
lock (_gate)
{
return _changed.Token;
}
}
}
/// <summary>面板下发的设置;为空表示面板关闭了定时重启。返回 false 表示文本不合法(节点忽略它)。</summary>
public bool SetRemote(string? text)
{
RestartSchedule? schedule = null;
if (!string.IsNullOrWhiteSpace(text) && !RestartSchedule.TryParse(text, out schedule))
{
return false;
}
CancellationTokenSource previous;
lock (_gate)
{
_remote = schedule;
previous = _changed;
_changed = new CancellationTokenSource();
}
previous.Cancel();
previous.Dispose();
return true;
}
public void Dispose()
{
lock (_gate)
{
_changed.Dispose();
}
}
}