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

+10 -1
View File
@@ -23,7 +23,7 @@ public sealed class ProbeApp : IDisposable
private readonly INodeLog _log;
private readonly FleetLink _link;
public ProbeApp(ProbeFile file, string configDirectory, TimeProvider time, INodeLog log)
public ProbeApp(ProbeFile file, string configDirectory, TimeProvider time, INodeLog log, RestartController? restart = null)
{
_log = log;
var directory = new AgentDirectory(new ConfigStore(configDirectory), configDirectory, log);
@@ -59,6 +59,15 @@ public sealed class ProbeApp : IDisposable
.OnNotify(MoShiroMethods.UpdateApply, MoShiroJsonContext.Default.UpdateOfferParams, (_, _, _) =>
{
update.RequestApply();
return ValueTask.CompletedTask;
})
.OnNotify(MoShiroMethods.Schedule, MoShiroJsonContext.Default.ScheduleParams, (_, schedule, _) =>
{
if (restart is not null && !restart.SetRemote(schedule.RestartAt))
{
log.Warn("ignoring an invalid restart schedule from the panel");
}
return ValueTask.CompletedTask;
});
_link = new FleetLink(options, router, [list], new Outbox(1 << 20), time, log);
@@ -20,6 +20,10 @@ public sealed class ProbeFile
[JsonPropertyName("server")]
public string Server { get; set; } = "";
/// <summary>每天定时重启一次,例如 <c>04:00+08:00</c>(不写偏移按 UTC);不写就不重启。环境变量 <c>MOSHIRO_RESTART_AT</c> 优先;这里是本地配置,从面板重新下载 probe.json 会丢掉它,所以容器里推荐用环境变量。</summary>
[JsonPropertyName("restart_at")]
public string? RestartAt { get; set; }
[JsonPropertyName("limits")]
public ProbeLimits Limits { get; set; } = new();
}
+5 -2
View File
@@ -21,9 +21,11 @@ for (int i = 0; i < args.Length - 1; i++)
}
ProbeFile file;
RestartController restart;
try
{
file = NodeConfig.Load(configPath, ProbeConfigContext.Default.ProbeFile);
restart = new RestartController(RestartSchedule.Resolve(file.RestartAt));
if (file.ProbeId.Length == 0 || file.PrivateKey.Length == 0 || !Uri.TryCreate(file.Server, UriKind.Absolute, out _))
{
throw new InvalidOperationException("probe.json needs probe_id, private_key and server (download it from the panel: Probes → Create)");
@@ -35,11 +37,12 @@ catch (Exception ex) when (ex is IOException or InvalidDataException or InvalidO
return 1;
}
using var restartScope = restart;
string directory = Path.GetDirectoryName(Path.GetFullPath(configPath))!;
try
{
using var app = new ProbeApp(file, directory, time, log);
await ServiceShell.RunAsync(app.RunAsync, log);
using var app = new ProbeApp(file, directory, time, log, restart);
await ServiceShell.RunAsync(app.RunAsync, log, restart, time);
}
catch (Exception ex) when (ex is FormatException or System.Security.Cryptography.CryptographicException)
{