From d948ba4135ce2997d362ba31114e98c1da9362d8 Mon Sep 17 00:00:00 2001 From: Pilzinsel64 Date: Wed, 22 Jan 2025 15:20:39 +0100 Subject: [PATCH] auto-restart on fatal http error --- Pilz.Net/Api/ApiServer.cs | 52 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/Pilz.Net/Api/ApiServer.cs b/Pilz.Net/Api/ApiServer.cs index 55446c7..3078a3d 100644 --- a/Pilz.Net/Api/ApiServer.cs +++ b/Pilz.Net/Api/ApiServer.cs @@ -13,7 +13,9 @@ public class ApiServer(string apiUrl) : IApiServer { protected readonly List handlers = []; protected readonly Dictionary serializers = []; - protected readonly HttpListener httpListener = new(); + protected HttpListener httpListener = new(); + protected int restartAttempts = 0; + protected DateTime lastRestartAttempt; public event OnCheckAuthenticationEventHandler? OnCheckAuthentication; public event OnCheckContextEventHandler? OnCheckContext; @@ -37,18 +39,48 @@ public class ApiServer(string apiUrl) : IApiServer public bool AllowMultipleRequests { get; set; } + public int StopDelay { get; set; } = 5000; + + public int AutoRestartOnError { get; set; } = 5000; + + public int MaxAutoRestartsPerMinute { get; set; } = 10; + public virtual void Start() { - Log.Info("Start listening"); + Log.Info("Starting listener"); httpListener.Prefixes.Add(ApiUrl + "/"); httpListener.Start(); + Log.Info("Started listener"); Receive(); } public virtual void Stop() { + Log.Info("Stopping listener"); httpListener.Stop(); - Log.Info("Stopped listening"); + Thread.Sleep(StopDelay); + httpListener.Close(); + Log.Info("Stopped listener"); + } + + public virtual bool Restart() + { + if (restartAttempts > MaxAutoRestartsPerMinute) + return false; + + var now = DateTime.Now; + if (now - lastRestartAttempt > TimeSpan.FromMinutes(1)) + lastRestartAttempt = now; + + restartAttempts += 1; + + Log.Info("Restarting listener"); + Stop(); + httpListener = new(); + Start(); + Log.Info("Restarted listener"); + + return true; } public virtual void RegisterHandler(T instance) where T : class @@ -130,6 +162,18 @@ public class ApiServer(string apiUrl) : IApiServer { context = httpListener.EndGetContext(result); } + catch (HttpListenerException ex) + { + if (ex.ErrorCode == 995 || ex.ErrorCode == 64) + { + Log.Fatal($"Fatal http error retriving context with code {ex.ErrorCode}", ex); + if (Restart()) // Try restart the server and skip this context + return; + } + else + Log.Error($"Http error retriving context with code {ex.ErrorCode}", ex); + context = null; + } catch (Exception ex) { Log.Error("Error retriving context", ex); @@ -251,11 +295,13 @@ public class ApiServer(string apiUrl) : IApiServer context.Response.ContentType = "application/json"; using StreamWriter output = new(context.Response.OutputStream); output.Write(resultJson); + output.Flush(); } else if (result.ResultContent is byte[] resultBytes) { Log.Info("Sending raw bytes response for " + context.Request.RawUrl); context.Response.OutputStream.Write(resultBytes, 0, resultBytes.Length); + context.Response.OutputStream.Flush(); } Log.Debug("Finish response");