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
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:
1 parent
388619b8b6
commit
9bcef56497
37 files changed
+928
-101
No files matched your search
@@ -53,11 +53,13 @@ public sealed class MoShiroNodeEventSink : INodeEventSink
|
||||
private readonly AgentService _service;
|
||||
private readonly NodeInfoService _nodes;
|
||||
private readonly ReleaseService _releases;
|
||||
private readonly ScheduleService _schedule;
|
||||
private readonly IProbeStore _probes;
|
||||
|
||||
public MoShiroNodeEventSink(IAgentStore agents, AgentRuntime runtime, IEventStore events, LiveHub live, AgentService service, NodeInfoService nodes, ReleaseService releases, IProbeStore probes)
|
||||
public MoShiroNodeEventSink(IAgentStore agents, AgentRuntime runtime, IEventStore events, LiveHub live, AgentService service, NodeInfoService nodes, ReleaseService releases, ScheduleService schedule, IProbeStore probes)
|
||||
{
|
||||
_releases = releases;
|
||||
_schedule = schedule;
|
||||
_probes = probes;
|
||||
_nodes = nodes;
|
||||
_agents = agents;
|
||||
@@ -144,6 +146,7 @@ public sealed class MoShiroNodeEventSink : INodeEventSink
|
||||
}
|
||||
|
||||
await _releases.OfferToNodeAsync(id, ct);
|
||||
await _schedule.SendToNodeAsync(id, ct);
|
||||
break;
|
||||
case NodeEventKind.Offline:
|
||||
_live.Publish(new NodeSignal("probe", id.Value, false, nodeEvent.AtMs));
|
||||
@@ -214,6 +217,7 @@ public sealed class MoShiroNodeEventSink : INodeEventSink
|
||||
AgentRecord? after = await _agents.GetAsync(id, ct);
|
||||
_nodes.ObserveAgentInBackground(id.Value, after?.PublicHost, meta.Platform);
|
||||
await _releases.OfferToNodeAsync(id, ct);
|
||||
await _schedule.SendToNodeAsync(id, ct);
|
||||
if (before is not null && after is not null
|
||||
&& (!before.TlsSpki.AsSpan().SequenceEqual(after.TlsSpki) || before.ProbeTcpPort != after.ProbeTcpPort || !before.ProbeUdpPorts.SequenceEqual(after.ProbeUdpPorts) || before.Ipv6Supported != after.Ipv6Supported)
|
||||
&& after.Status == NodeStatus.Active)
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
using System.Globalization;
|
||||
using Fleet.Core;
|
||||
|
||||
namespace MoShiro.Backend.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 节点的定时重启:设置在管理端(开关、时刻、时区偏移),节点连上时补发、设置变化时群发给所有在线节点。
|
||||
/// 面板只告诉节点「几点退出」,节点自己到点有序退出、由服务管理器拉起;节点本地写了设置时以本地为准。
|
||||
/// </summary>
|
||||
public sealed class ScheduleService
|
||||
{
|
||||
private readonly SettingsService _settings;
|
||||
private readonly IAgentGateway _gateway;
|
||||
|
||||
public ScheduleService(SettingsService settings, IAgentGateway gateway)
|
||||
{
|
||||
_settings = settings;
|
||||
_gateway = gateway;
|
||||
}
|
||||
|
||||
/// <summary>形如 <c>04:30+08:00</c>;开关关着时为空。</summary>
|
||||
public async ValueTask<string?> RestartAtAsync(CancellationToken ct)
|
||||
{
|
||||
if (!await _settings.GetBoolAsync(SettingsService.RestartEnabled, ct))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Format(
|
||||
await _settings.GetIntAsync(SettingsService.RestartHour, ct),
|
||||
await _settings.GetIntAsync(SettingsService.RestartMinute, ct),
|
||||
await _settings.GetIntAsync(SettingsService.RestartOffsetMinutes, ct));
|
||||
}
|
||||
|
||||
public static string Format(int hour, int minute, int offsetMinutes)
|
||||
{
|
||||
int abs = Math.Abs(offsetMinutes);
|
||||
return string.Create(CultureInfo.InvariantCulture, $"{hour:00}:{minute:00}{(offsetMinutes < 0 ? '-' : '+')}{abs / 60:00}:{abs % 60:00}");
|
||||
}
|
||||
|
||||
/// <summary>节点刚连上:补发当前设置(节点离线时改的设置也不会错过)。</summary>
|
||||
public async ValueTask SendToNodeAsync(NodeId node, CancellationToken ct) =>
|
||||
await _gateway.NotifyScheduleAsync(node, await RestartAtAsync(ct), ct);
|
||||
|
||||
/// <summary>管理端改了设置:通知所有在线节点。</summary>
|
||||
public async ValueTask SendToAllAsync(CancellationToken ct)
|
||||
{
|
||||
string? restartAt = await RestartAtAsync(ct);
|
||||
foreach (NodeId node in _gateway.OnlineNodes)
|
||||
{
|
||||
await _gateway.NotifyScheduleAsync(node, restartAt, ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user