From 776d76d299748a79b9cb25593cd8266cb26a6553 Mon Sep 17 00:00:00 2001 From: Dan Engelbrecht Date: Fri, 27 Mar 2026 11:13:02 +0100 Subject: idle deprovision in hub (#895) - Feature: Hub watchdog automatically deprovisions inactive provisioned and hibernated instances - Feature: Added `stats/activity_counters` endpoint to measure server activity - Feature: Added configuration options for hub watchdog - `--hub-watchdog-provisioned-inactivity-timeout-seconds` Inactivity timeout before a provisioned instance is deprovisioned - `--hub-watchdog-hibernated-inactivity-timeout-seconds` Inactivity timeout before a hibernated instance is deprovisioned - `--hub-watchdog-inactivity-check-margin-seconds` Margin before timeout at which an activity check is issued - `--hub-watchdog-cycle-interval-ms` Watchdog poll interval in milliseconds - `--hub-watchdog-cycle-processing-budget-ms` Maximum time budget per watchdog cycle in milliseconds - `--hub-watchdog-instance-check-throttle-ms` Minimum delay between checks on a single instance - `--hub-watchdog-activity-check-connect-timeout-ms` Connect timeout for activity check requests - `--hub-watchdog-activity-check-request-timeout-ms` Request timeout for activity check requests --- src/zenhttp/httpclient.cpp | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'src/zenhttp/httpclient.cpp') diff --git a/src/zenhttp/httpclient.cpp b/src/zenhttp/httpclient.cpp index 4000ea8a8..96107883e 100644 --- a/src/zenhttp/httpclient.cpp +++ b/src/zenhttp/httpclient.cpp @@ -401,6 +401,13 @@ HttpClient::~HttpClient() delete m_Inner; } +void +HttpClient::SetBaseUri(std::string_view NewBaseUri) +{ + m_BaseUri = NewBaseUri; + m_Inner->SetBaseUri(NewBaseUri); +} + void HttpClient::SetSessionId(const Oid& SessionId) { @@ -980,6 +987,71 @@ TEST_CASE("httpclient.password") AsioServer->RequestExit(); } } +TEST_CASE("httpclient.setbaseuri") +{ + struct TestHttpService : public HttpService + { + explicit TestHttpService(std::string_view Identity) : m_Identity(Identity) {} + + virtual const char* BaseUri() const override { return "/test/"; } + virtual void HandleRequest(HttpServerRequest& Req) override + { + Req.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, m_Identity); + } + + std::string m_Identity; + }; + + ScopedTemporaryDirectory TmpDir1; + ScopedTemporaryDirectory TmpDir2; + TestHttpService Service1("server-one"); + TestHttpService Service2("server-two"); + + Ref Server1 = CreateHttpAsioServer(AsioConfig{}); + Ref Server2 = CreateHttpAsioServer(AsioConfig{}); + + int Port1 = Server1->Initialize(0, TmpDir1.Path()); + int Port2 = Server2->Initialize(0, TmpDir2.Path()); + REQUIRE(Port1 != -1); + REQUIRE(Port2 != -1); + + Server1->RegisterService(Service1); + Server2->RegisterService(Service2); + + std::thread Thread1([&]() { Server1->Run(false); }); + std::thread Thread2([&]() { Server2->Run(false); }); + + auto _ = MakeGuard([&]() { + if (Thread1.joinable()) + { + Thread1.join(); + } + if (Thread2.joinable()) + { + Thread2.join(); + } + Server1->Close(); + Server2->Close(); + }); + + HttpClient Client(fmt::format("127.0.0.1:{}", Port1), HttpClientSettings{}, {}); + CHECK_EQ(Client.GetBaseUri(), fmt::format("127.0.0.1:{}", Port1)); + + HttpClient::Response Resp1 = Client.Get("/test/hello"); + CHECK(Resp1.IsSuccess()); + CHECK_EQ(Resp1.AsText(), "server-one"); + + Client.SetBaseUri(fmt::format("127.0.0.1:{}", Port2)); + CHECK_EQ(Client.GetBaseUri(), fmt::format("127.0.0.1:{}", Port2)); + + HttpClient::Response Resp2 = Client.Get("/test/hello"); + CHECK(Resp2.IsSuccess()); + CHECK_EQ(Resp2.AsText(), "server-two"); + + Server1->RequestExit(); + Server2->RequestExit(); +} + TEST_SUITE_END(); void -- cgit v1.2.3