From 232c94c61f6ff4c2745599dc97b821c62e51ef26 Mon Sep 17 00:00:00 2001 From: Pilzinsel64 Date: Fri, 24 Jan 2025 06:10:43 +0100 Subject: [PATCH] use SemaphoreSlim to limit the amount of parallel http requests --- Pilz.Net/Api/ApiServer.cs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/Pilz.Net/Api/ApiServer.cs b/Pilz.Net/Api/ApiServer.cs index b68d680..ae8dd5d 100644 --- a/Pilz.Net/Api/ApiServer.cs +++ b/Pilz.Net/Api/ApiServer.cs @@ -16,6 +16,7 @@ public class ApiServer(string apiUrl) : IApiServer protected HttpListener httpListener = new(); protected int restartAttempts = 0; protected DateTime lastRestartAttempt; + protected SemaphoreSlim? semaphore; public event OnCheckAuthenticationEventHandler? OnCheckAuthentication; public event OnCheckContextEventHandler? OnCheckContext; @@ -45,6 +46,8 @@ public class ApiServer(string apiUrl) : IApiServer public int MaxAutoRestartsPerMinute { get; set; } = 10; + public int MaxConcurentConnections { get; set; } = 5; + public virtual void Start() { Log.Info("Starting listener"); @@ -68,6 +71,7 @@ public class ApiServer(string apiUrl) : IApiServer Log.Info("Restarting listener"); Stop(); httpListener = new(); + semaphore?.Release(int.MaxValue); Start(); Log.Info("Restarted listener"); } @@ -92,6 +96,17 @@ public class ApiServer(string apiUrl) : IApiServer return true; } + protected virtual void WaitForSlot() + { + semaphore ??= new(MaxConcurentConnections); + semaphore.Wait(); + } + + protected virtual void FreeSlot() + { + semaphore?.Release(); + } + public virtual void RegisterHandler(T instance) where T : class { // Get all public instance methods @@ -166,6 +181,18 @@ public class ApiServer(string apiUrl) : IApiServer if (!httpListener.IsListening) return; + // Wait for a free slot + try + { + WaitForSlot(); + } + catch (Exception ex) + { + Log.Fatal($"Too many concurent connections", ex); + Thread.Sleep(1000); + return; + } + // Get context try { @@ -195,7 +222,10 @@ public class ApiServer(string apiUrl) : IApiServer // Cancel if we don't have a context if (context is null) + { + FreeSlot(); return; + } // Check context Log.Info("Request retrived for " + context.Request.RawUrl); @@ -215,6 +245,9 @@ public class ApiServer(string apiUrl) : IApiServer OnCheckContextCompleted?.Invoke(this, new(context)); } + // Release slot + FreeSlot(); + // Listen for new request if (!AllowMultipleRequests) Receive();