changeset 6227:71e404609278

orthanc_available_http_threads
author Alain Mazy <am@orthanc.team>
date Mon, 07 Jul 2025 19:28:34 +0200
parents da6430b05c8d
children c3fb276f8eba
files NEWS OrthancFramework/Sources/HttpServer/HttpServer.cpp OrthancFramework/Sources/HttpServer/HttpServer.h OrthancFramework/Sources/MetricsRegistry.cpp OrthancFramework/Sources/MetricsRegistry.h OrthancFramework/UnitTestsSources/FrameworkTests.cpp OrthancFramework/UnitTestsSources/RestApiTests.cpp OrthancServer/Sources/main.cpp
diffstat 8 files changed, 77 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Mon Jul 07 17:13:09 2025 +0200
+++ b/NEWS	Mon Jul 07 19:28:34 2025 +0200
@@ -14,6 +14,12 @@
   /jobs/{jobId} route.
 * New metrics "orthanc_available_dicom_threads" that displays the minimum
   number of DICOM Threads that were available during the last 10 seconds.
+* New metrics "orthanc_available_http_threads" that displays the minimum
+  number of HTTP Threads that were available during the last 10 seconds.
+  It is basically the opposite of "orthanc_rest_api_active_requests" but
+  it is more convenient to configure alerts on.  "orthanc_rest_api_active_requests"
+  also monitors the internal requests coming from plugins while "orthanc_available_http_threads"
+  monitors the requests received by the external HTTP Server.
 * Fixed the "orthanc_rest_api_active_requests" metrix that was not 
   reset after 10 seconds.
 
--- a/OrthancFramework/Sources/HttpServer/HttpServer.cpp	Mon Jul 07 17:13:09 2025 +0200
+++ b/OrthancFramework/Sources/HttpServer/HttpServer.cpp	Mon Jul 07 19:28:34 2025 +0200
@@ -32,6 +32,7 @@
 #include "../Logging.h"
 #include "../OrthancException.h"
 #include "../TemporaryFile.h"
+#include "../MetricsRegistry.h"
 #include "HttpToolbox.h"
 #include "IHttpHandler.h"
 #include "MultipartStreamReader.h"
@@ -1155,6 +1156,8 @@
   {
     bool localhost;
 
+    MetricsRegistry::AvailableResourcesDecounter counter(server.GetAvailableHttpThreadsMetrics());
+
 #if ORTHANC_ENABLE_MONGOOSE == 1
     static const long LOCALHOST = (127ll << 24) + 1ll;
     localhost = (request->remote_ip == LOCALHOST);
@@ -1609,7 +1612,7 @@
   }
 
 
-  HttpServer::HttpServer() :
+  HttpServer::HttpServer(MetricsRegistry& metricsRegistry) :
     pimpl_(new PImpl),
     handler_(NULL),
     remoteAllowed_(false),
@@ -1628,7 +1631,10 @@
     threadsCount_(50),  // Default value in mongoose/civetweb
     tcpNoDelay_(true),
     requestTimeout_(30),  // Default value in mongoose/civetweb (30 seconds)
-    redirectNotAuthenticatedToRoot_(false)
+    redirectNotAuthenticatedToRoot_(false),
+    availableHttpThreadsMetrics_(metricsRegistry,
+                                 "orthanc_available_http_threads_count",
+                                 MetricsUpdatePolicy_MinOver10Seconds)
   {
 #if ORTHANC_ENABLE_MONGOOSE == 1
     CLOG(INFO, HTTP) << "This Orthanc server uses Mongoose as its embedded HTTP server";
@@ -2145,6 +2151,7 @@
     
     Stop();
     threadsCount_ = threads;
+    availableHttpThreadsMetrics_.SetInitialValue(threadsCount_);
 
     CLOG(INFO, HTTP) << "The embedded HTTP server will use " << threads << " threads";
   }
--- a/OrthancFramework/Sources/HttpServer/HttpServer.h	Mon Jul 07 17:13:09 2025 +0200
+++ b/OrthancFramework/Sources/HttpServer/HttpServer.h	Mon Jul 07 19:28:34 2025 +0200
@@ -50,6 +50,7 @@
 
 
 #include "IIncomingHttpRequestFilter.h"
+#include "../MetricsRegistry.h"
 
 #include <list>
 #include <map>
@@ -115,6 +116,7 @@
     bool tcpNoDelay_;
     unsigned int requestTimeout_;  // In seconds
     bool redirectNotAuthenticatedToRoot_;  // New in Orthanc 1.12.9
+    MetricsRegistry::SharedMetrics availableHttpThreadsMetrics_;
 
 #if ORTHANC_ENABLE_PUGIXML == 1
     WebDavBuckets webDavBuckets_;
@@ -123,7 +125,7 @@
     bool IsRunning() const;
 
   public:
-    HttpServer();
+    HttpServer(MetricsRegistry& metricsRegistry);
 
     ~HttpServer();
 
@@ -231,5 +233,10 @@
     bool IsRedirectNotAuthenticatedToRoot() const;
 
     void SetRedirectNotAuthenticatedToRoot(bool redirect);
+
+    MetricsRegistry::SharedMetrics& GetAvailableHttpThreadsMetrics()
+    {
+      return availableHttpThreadsMetrics_;
+    }
   };
 }
--- a/OrthancFramework/Sources/MetricsRegistry.cpp	Mon Jul 07 17:13:09 2025 +0200
+++ b/OrthancFramework/Sources/MetricsRegistry.cpp	Mon Jul 07 19:28:34 2025 +0200
@@ -262,6 +262,8 @@
     virtual std::string FormatValue() const = 0;
 
     virtual void Refresh() = 0;
+
+    virtual void SetInitialValue(int64_t value) = 0;
   };
 
   
@@ -316,6 +318,10 @@
       value_.Refresh(GetPolicy());
     }
 
+    virtual void SetInitialValue(int64_t value) ORTHANC_OVERRIDE
+    {
+      value_.Update(value, MetricsUpdatePolicy_Directly);
+    }
   };
 
   
@@ -369,6 +375,11 @@
     {
       value_.Refresh(GetPolicy());
     }
+
+    virtual void SetInitialValue(int64_t value) ORTHANC_OVERRIDE
+    {
+      value_.Update(value, MetricsUpdatePolicy_Directly);
+    }
   };
 
 
@@ -488,6 +499,16 @@
     }
   }
 
+  void MetricsRegistry::SetInitialValue(const std::string& name,
+                                        int64_t value)
+  {
+    if (enabled_)
+    {
+      boost::mutex::scoped_lock lock(mutex_);
+      GetItemInternal(name, MetricsUpdatePolicy_Directly, MetricsDataType_Integer).SetInitialValue(value);
+    }
+  }
+
 
   MetricsUpdatePolicy MetricsRegistry::GetUpdatePolicy(const std::string& metrics)
   {
@@ -581,6 +602,12 @@
     registry_.SetIntegerValue(name_, value_);
   }
 
+  void MetricsRegistry::SharedMetrics::SetInitialValue(int64_t value)
+  {
+    boost::mutex::scoped_lock lock(mutex_);
+    value_ = value;
+    registry_.SetInitialValue(name_, value_);
+  }
 
   MetricsRegistry::ActiveCounter::ActiveCounter(MetricsRegistry::SharedMetrics &metrics) :
     metrics_(metrics)
--- a/OrthancFramework/Sources/MetricsRegistry.h	Mon Jul 07 17:13:09 2025 +0200
+++ b/OrthancFramework/Sources/MetricsRegistry.h	Mon Jul 07 19:28:34 2025 +0200
@@ -106,6 +106,9 @@
       SetIntegerValue(name, value, MetricsUpdatePolicy_Directly);
     }
     
+    void SetInitialValue(const std::string& name,
+                         int64_t value);
+
     void IncrementIntegerValue(const std::string& name,
                                int64_t delta);
 
@@ -131,6 +134,8 @@
                     MetricsUpdatePolicy policy);
 
       void Add(int64_t delta);
+
+      void SetInitialValue(int64_t value);
     };
 
 
--- a/OrthancFramework/UnitTestsSources/FrameworkTests.cpp	Mon Jul 07 17:13:09 2025 +0200
+++ b/OrthancFramework/UnitTestsSources/FrameworkTests.cpp	Mon Jul 07 19:28:34 2025 +0200
@@ -1611,16 +1611,17 @@
       GetValuesDico(values, mr);
       ASSERT_EQ("2", values["shared_max10"]);
 
-      // // Uncomment to test max values going back to latest values after expiration of the 10 seconds period
-      // boost::this_thread::sleep(boost::posix_time::milliseconds(12000));
+      // { // Uncomment to test max values going back to latest values after expiration of the 10 seconds period
+      //   boost::this_thread::sleep(boost::posix_time::milliseconds(12000));
 
-      // GetValuesDico(values, mr);
-      // ASSERT_EQ("0", values["shared_max10"]);
+      //   GetValuesDico(values, mr);
+      //   ASSERT_EQ("0", values["shared_max10"]);
+      // }
     }
 
     {
       MetricsRegistry::SharedMetrics min10(mr, "shared_min10", MetricsUpdatePolicy_MinOver10Seconds);
-      min10.Add(10);
+      min10.SetInitialValue(10);
 
       GetValuesDico(values, mr);
       ASSERT_EQ("10", values["shared_min10"]);
@@ -1635,11 +1636,17 @@
       GetValuesDico(values, mr);
       ASSERT_EQ("8", values["shared_min10"]);
 
-      // // Uncomment to test min values going back to latest values after expiration of the 10 seconds period
-      // boost::this_thread::sleep(boost::posix_time::milliseconds(12000));
+      // {
+      //   // Uncomment to test min values going back to latest values after expiration of the 10 seconds period
+      //   boost::this_thread::sleep(boost::posix_time::milliseconds(12000));
 
-      // GetValuesDico(values, mr);
-      // ASSERT_EQ("10", values["shared_min10"]);
+      //   GetValuesDico(values, mr);
+      //   ASSERT_EQ("10", values["shared_min10"]);
+      // }
+
+      min10.SetInitialValue(5);
+      GetValuesDico(values, mr);
+      ASSERT_EQ("5", values["shared_min10"]);
     }
   }
 }
--- a/OrthancFramework/UnitTestsSources/RestApiTests.cpp	Mon Jul 07 17:13:09 2025 +0200
+++ b/OrthancFramework/UnitTestsSources/RestApiTests.cpp	Mon Jul 07 19:28:34 2025 +0200
@@ -38,6 +38,7 @@
 #include "../Sources/OrthancException.h"
 #include "../Sources/RestApi/RestApiHierarchy.h"
 #include "../Sources/WebServiceParameters.h"
+#include "../Sources/MetricsRegistry.h"
 
 #include <ctype.h>
 #include <boost/lexical_cast.hpp>
@@ -1330,9 +1331,9 @@
 TEST(HttpClient, DISABLED_Issue156_Slow)
 {
   // https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=156
-  
+  MetricsRegistry dummyRegistry;
   TotoServer handler;
-  HttpServer server;
+  HttpServer server(dummyRegistry);
   server.SetPortNumber(5000);
   server.Register(handler);
   server.Start();
@@ -1359,8 +1360,9 @@
 
 TEST(HttpClient, DISABLED_Issue156_Crash)
 {
+  MetricsRegistry dummyRegistry;
   TotoServer handler;
-  HttpServer server;
+  HttpServer server(dummyRegistry);
   server.SetPortNumber(5000);
   server.Register(handler);
   server.Start();
--- a/OrthancServer/Sources/main.cpp	Mon Jul 07 17:13:09 2025 +0200
+++ b/OrthancServer/Sources/main.cpp	Mon Jul 07 19:28:34 2025 +0200
@@ -1032,7 +1032,7 @@
   else
   {
     MyIncomingHttpRequestFilter httpFilter(context, plugins);
-    HttpServer httpServer;
+    HttpServer httpServer(context.GetMetricsRegistry());
     bool httpDescribeErrors;
 
 #if ORTHANC_ENABLE_MONGOOSE == 1