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:
|
case "--https_port" when i + 1 < args.Length:
|
||||||
options.MonitorHttpsPort = int.Parse(args[++i]);
|
options.MonitorHttpsPort = int.Parse(args[++i]);
|
||||||
break;
|
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":
|
case "--tls":
|
||||||
break;
|
break;
|
||||||
case "--tlscert" when i + 1 < args.Length:
|
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);
|
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) =>
|
Console.CancelKeyPress += (_, e) =>
|
||||||
{
|
{
|
||||||
e.Cancel = true;
|
e.Cancel = true;
|
||||||
cts.Cancel();
|
Log.Information("Trapped SIGINT signal");
|
||||||
|
_ = Task.Run(async () => await server.ShutdownAsync());
|
||||||
};
|
};
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await server.StartAsync(cts.Token);
|
_ = server.StartAsync(CancellationToken.None);
|
||||||
|
await server.WaitForReadyAsync();
|
||||||
|
server.WaitForShutdown();
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using System.Collections.Concurrent;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Security;
|
using System.Net.Security;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@@ -42,6 +43,8 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
|
|||||||
|
|
||||||
private int _lameDuck;
|
private int _lameDuck;
|
||||||
|
|
||||||
|
private readonly List<PosixSignalRegistration> _signalRegistrations = [];
|
||||||
|
|
||||||
private string? _portsFilePath;
|
private string? _portsFilePath;
|
||||||
|
|
||||||
private static readonly TimeSpan AcceptMinSleep = TimeSpan.FromMilliseconds(10);
|
private static readonly TimeSpan AcceptMinSleep = TimeSpan.FromMilliseconds(10);
|
||||||
@@ -187,6 +190,50 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
|
|||||||
await ShutdownAsync();
|
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)
|
public NatsServer(NatsOptions options, ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
_options = options;
|
_options = options;
|
||||||
@@ -561,6 +608,8 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
|
|||||||
{
|
{
|
||||||
if (!IsShuttingDown)
|
if (!IsShuttingDown)
|
||||||
ShutdownAsync().GetAwaiter().GetResult();
|
ShutdownAsync().GetAwaiter().GetResult();
|
||||||
|
foreach (var reg in _signalRegistrations)
|
||||||
|
reg.Dispose();
|
||||||
_quitCts.Dispose();
|
_quitCts.Dispose();
|
||||||
_tlsRateLimiter?.Dispose();
|
_tlsRateLimiter?.Dispose();
|
||||||
_listener?.Dispose();
|
_listener?.Dispose();
|
||||||
|
|||||||
Reference in New Issue
Block a user