feat: add signal handling (SIGTERM, SIGUSR2, SIGHUP) and CLI stubs
This commit is contained in:
@@ -32,6 +32,15 @@ for (int i = 0; i < args.Length; i++)
|
||||
case "--https_port" when i + 1 < args.Length:
|
||||
options.MonitorHttpsPort = int.Parse(args[++i]);
|
||||
break;
|
||||
case "-c" when i + 1 < args.Length:
|
||||
options.ConfigFile = args[++i];
|
||||
break;
|
||||
case "--pid" when i + 1 < args.Length:
|
||||
options.PidFile = args[++i];
|
||||
break;
|
||||
case "--ports_file_dir" when i + 1 < args.Length:
|
||||
options.PortsFileDir = args[++i];
|
||||
break;
|
||||
case "--tls":
|
||||
break;
|
||||
case "--tlscert" when i + 1 < args.Length:
|
||||
@@ -50,18 +59,24 @@ for (int i = 0; i < args.Length; i++)
|
||||
}
|
||||
|
||||
using var loggerFactory = new Serilog.Extensions.Logging.SerilogLoggerFactory(Log.Logger);
|
||||
var server = new NatsServer(options, loggerFactory);
|
||||
using var server = new NatsServer(options, loggerFactory);
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
// Register signal handlers
|
||||
server.HandleSignals();
|
||||
|
||||
// Ctrl+C triggers graceful shutdown
|
||||
Console.CancelKeyPress += (_, e) =>
|
||||
{
|
||||
e.Cancel = true;
|
||||
cts.Cancel();
|
||||
Log.Information("Trapped SIGINT signal");
|
||||
_ = Task.Run(async () => await server.ShutdownAsync());
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await server.StartAsync(cts.Token);
|
||||
_ = server.StartAsync(CancellationToken.None);
|
||||
await server.WaitForReadyAsync();
|
||||
server.WaitForShutdown();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Collections.Concurrent;
|
||||
using System.Net;
|
||||
using System.Net.Security;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -42,6 +43,8 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
|
||||
|
||||
private int _lameDuck;
|
||||
|
||||
private readonly List<PosixSignalRegistration> _signalRegistrations = [];
|
||||
|
||||
private string? _portsFilePath;
|
||||
|
||||
private static readonly TimeSpan AcceptMinSleep = TimeSpan.FromMilliseconds(10);
|
||||
@@ -187,6 +190,50 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
|
||||
await ShutdownAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers Unix signal handlers.
|
||||
/// SIGTERM → shutdown, SIGUSR2 → lame duck, SIGUSR1 → log reopen (stub), SIGHUP → reload (stub).
|
||||
/// </summary>
|
||||
public void HandleSignals()
|
||||
{
|
||||
_signalRegistrations.Add(PosixSignalRegistration.Create(PosixSignal.SIGTERM, ctx =>
|
||||
{
|
||||
ctx.Cancel = true;
|
||||
_logger.LogInformation("Trapped SIGTERM signal");
|
||||
_ = Task.Run(async () => await ShutdownAsync());
|
||||
}));
|
||||
|
||||
_signalRegistrations.Add(PosixSignalRegistration.Create(PosixSignal.SIGQUIT, ctx =>
|
||||
{
|
||||
ctx.Cancel = true;
|
||||
_logger.LogInformation("Trapped SIGQUIT signal");
|
||||
_ = Task.Run(async () => await ShutdownAsync());
|
||||
}));
|
||||
|
||||
_signalRegistrations.Add(PosixSignalRegistration.Create(PosixSignal.SIGHUP, ctx =>
|
||||
{
|
||||
ctx.Cancel = true;
|
||||
_logger.LogWarning("Trapped SIGHUP signal — config reload not yet supported");
|
||||
}));
|
||||
|
||||
// SIGUSR1 and SIGUSR2 only on non-Windows
|
||||
if (!OperatingSystem.IsWindows())
|
||||
{
|
||||
_signalRegistrations.Add(PosixSignalRegistration.Create((PosixSignal)10, ctx =>
|
||||
{
|
||||
ctx.Cancel = true;
|
||||
_logger.LogWarning("Trapped SIGUSR1 signal — log reopen not yet supported");
|
||||
}));
|
||||
|
||||
_signalRegistrations.Add(PosixSignalRegistration.Create((PosixSignal)12, ctx =>
|
||||
{
|
||||
ctx.Cancel = true;
|
||||
_logger.LogInformation("Trapped SIGUSR2 signal — entering lame duck mode");
|
||||
_ = Task.Run(async () => await LameDuckShutdownAsync());
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
public NatsServer(NatsOptions options, ILoggerFactory loggerFactory)
|
||||
{
|
||||
_options = options;
|
||||
@@ -561,6 +608,8 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
|
||||
{
|
||||
if (!IsShuttingDown)
|
||||
ShutdownAsync().GetAwaiter().GetResult();
|
||||
foreach (var reg in _signalRegistrations)
|
||||
reg.Dispose();
|
||||
_quitCts.Dispose();
|
||||
_tlsRateLimiter?.Dispose();
|
||||
_listener?.Dispose();
|
||||
|
||||
Reference in New Issue
Block a user