aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver
diff options
context:
space:
mode:
Diffstat (limited to 'src/zenserver')
-rw-r--r--src/zenserver/diag/diagsvcs.cpp4
-rw-r--r--src/zenserver/hub/hubservice.cpp71
-rw-r--r--src/zenserver/hub/hubservice.h5
-rw-r--r--src/zenserver/hub/zenhubserver.cpp55
-rw-r--r--src/zenserver/hub/zenhubserver.h9
5 files changed, 134 insertions, 10 deletions
diff --git a/src/zenserver/diag/diagsvcs.cpp b/src/zenserver/diag/diagsvcs.cpp
index d8d53b0e3..e6811ef04 100644
--- a/src/zenserver/diag/diagsvcs.cpp
+++ b/src/zenserver/diag/diagsvcs.cpp
@@ -36,7 +36,7 @@ HttpHealthService::HttpHealthService()
"",
[](HttpRouterRequest& RoutedReq) {
HttpServerRequest& HttpReq = RoutedReq.ServerRequest();
- HttpReq.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, u8"OK!"sv);
+ HttpReq.WriteResponse(HttpResponseCode::OK);
},
HttpVerb::kGet);
@@ -118,7 +118,7 @@ HttpHealthService::HandleRequest(HttpServerRequest& Request)
ZEN_MEMSCOPE(GetHealthTag());
if (!m_Router.HandleRequest(Request))
{
- Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, u8"OK!"sv);
+ Request.WriteResponse(HttpResponseCode::OK);
}
}
diff --git a/src/zenserver/hub/hubservice.cpp b/src/zenserver/hub/hubservice.cpp
index bf0e294c5..cc34e86bb 100644
--- a/src/zenserver/hub/hubservice.cpp
+++ b/src/zenserver/hub/hubservice.cpp
@@ -8,9 +8,9 @@
#include <zencore/filesystem.h>
#include <zencore/fmtutils.h>
#include <zencore/logging.h>
-#include <zencore/process.h>
#include <zencore/scopeguard.h>
#include <zencore/system.h>
+#include <zenutil/consul.h>
#include <zenutil/zenserverprocess.h>
ZEN_THIRD_PARTY_INCLUDES_START
@@ -135,7 +135,8 @@ struct StorageServerInstance
StorageServerInstance(ZenServerEnvironment& RunEnvironment,
std::string_view ModuleId,
std::filesystem::path FileHydrationPath,
- std::filesystem::path HydrationTempPath);
+ std::filesystem::path HydrationTempPath,
+ consul::ConsulClient* ConsulClient = nullptr);
~StorageServerInstance();
void Provision();
@@ -169,6 +170,7 @@ private:
#if ZEN_PLATFORM_WINDOWS
JobObject* m_JobObject = nullptr;
#endif
+ consul::ConsulClient* m_ConsulClient;
void SpawnServerProcess();
@@ -179,10 +181,12 @@ private:
StorageServerInstance::StorageServerInstance(ZenServerEnvironment& RunEnvironment,
std::string_view ModuleId,
std::filesystem::path FileHydrationPath,
- std::filesystem::path HydrationTempPath)
+ std::filesystem::path HydrationTempPath,
+ consul::ConsulClient* ConsulClient)
: m_ModuleId(ModuleId)
, m_ServerInstance(RunEnvironment, ZenServerInstance::ServerMode::kStorageServer)
, m_HydrationPath(FileHydrationPath)
+, m_ConsulClient(ConsulClient)
{
m_BaseDir = RunEnvironment.CreateChildDir(ModuleId);
m_TempDir = HydrationTempPath / ModuleId;
@@ -234,6 +238,28 @@ StorageServerInstance::Provision()
SpawnServerProcess();
}
+ // Register with Consul if client is available
+ if (m_ConsulClient != nullptr)
+ {
+ consul::ServiceRegistrationInfo Info;
+ Info.ServiceId = m_ModuleId;
+ Info.ServiceName = "zen-service";
+ Info.Address = "localhost";
+ Info.Port = GetBasePort();
+ Info.HealthEndpoint = "health";
+ Info.HealthIntervalSeconds = 10;
+ Info.DeregisterAfterSeconds = 30;
+
+ if (!m_ConsulClient->RegisterService(Info))
+ {
+ ZEN_WARN("Failed to register storage server instance for module '{}' with Consul, continuing anyway", m_ModuleId);
+ }
+ else
+ {
+ ZEN_INFO("Registered storage server instance for module '{}' with Consul as '{}'", m_ModuleId, Info.ServiceName);
+ }
+ }
+
m_IsProvisioned = true;
}
@@ -251,6 +277,19 @@ StorageServerInstance::Deprovision()
ZEN_INFO("Deprovisioning storage server instance for module '{}'", m_ModuleId);
+ // Deregister from Consul before shutdown
+ if (m_ConsulClient != nullptr)
+ {
+ if (!m_ConsulClient->DeregisterService(m_ModuleId))
+ {
+ ZEN_WARN("Failed to deregister storage server instance for module '{}' from Consul, continuing anyway", m_ModuleId);
+ }
+ else
+ {
+ ZEN_INFO("Deregistered storage server instance for module '{}' from Consul", m_ModuleId);
+ }
+ }
+
m_ServerInstance.Shutdown();
Dehydrate();
@@ -445,9 +484,12 @@ struct HttpHubService::Impl
return false;
}
- IsNewInstance = true;
- auto NewInstance =
- std::make_unique<StorageServerInstance>(m_RunEnvironment, ModuleId, m_FileHydrationPath, m_HydrationTempPath);
+ IsNewInstance = true;
+ auto NewInstance = std::make_unique<StorageServerInstance>(m_RunEnvironment,
+ ModuleId,
+ m_FileHydrationPath,
+ m_HydrationTempPath,
+ m_ConsulClient);
#if ZEN_PLATFORM_WINDOWS
if (m_JobObject.IsValid())
{
@@ -625,6 +667,7 @@ private:
std::unordered_set<std::string> m_DeprovisioningModules;
std::unordered_set<std::string> m_ProvisioningModules;
int m_MaxInstanceCount = 0;
+ consul::ConsulClient* m_ConsulClient = nullptr;
void UpdateStats();
// Capacity tracking
@@ -635,6 +678,9 @@ private:
void UpdateCapacityMetrics();
bool CanProvisionInstance(std::string_view ModuleId, std::string& OutReason);
+
+public:
+ void SetConsulClient(consul::ConsulClient* Client) { m_ConsulClient = Client; }
};
HttpHubService::Impl::Impl()
@@ -718,7 +764,7 @@ HttpHubService::HttpHubService(std::filesystem::path HubBaseDir, std::filesystem
m_Router.AddMatcher("moduleid", [](std::string_view Str) -> bool {
for (const auto C : Str)
{
- if (std::isalnum(C) || C == '-')
+ if (std::isalnum(C) || C == '-' || C == ':')
{
// fine
}
@@ -749,6 +795,11 @@ HttpHubService::HttpHubService(std::filesystem::path HubBaseDir, std::filesystem
HttpVerb::kGet);
m_Router.RegisterRoute(
+ "health",
+ [](HttpRouterRequest& Req) { Req.ServerRequest().WriteResponse(HttpResponseCode::OK); },
+ HttpVerb::kGet);
+
+ m_Router.RegisterRoute(
"modules/{moduleid}",
[this](HttpRouterRequest& Req) {
std::string_view ModuleId = Req.GetCapture(1);
@@ -874,6 +925,12 @@ HttpHubService::SetNotificationEndpoint(std::string_view UpstreamNotificationEnd
}
void
+HttpHubService::SetConsulClient(consul::ConsulClient* Client)
+{
+ m_Impl->SetConsulClient(Client);
+}
+
+void
HttpHubService::HandleRequest(zen::HttpServerRequest& Request)
{
m_Router.HandleRequest(Request);
diff --git a/src/zenserver/hub/hubservice.h b/src/zenserver/hub/hubservice.h
index ef24bba69..0c5b5adb9 100644
--- a/src/zenserver/hub/hubservice.h
+++ b/src/zenserver/hub/hubservice.h
@@ -6,6 +6,10 @@
#include "hydration.h"
+namespace zen::consul {
+class ConsulClient;
+}
+
namespace zen {
/** ZenServer Hub Service
@@ -34,6 +38,7 @@ public:
* crashes or is force-killed. Must be called before Initialize(). No-op on non-Windows.
*/
void SetUseJobObject(bool Enable);
+ void SetConsulClient(consul::ConsulClient* Client);
private:
HttpRequestRouter m_Router;
diff --git a/src/zenserver/hub/zenhubserver.cpp b/src/zenserver/hub/zenhubserver.cpp
index d0a0db417..388008350 100644
--- a/src/zenserver/hub/zenhubserver.cpp
+++ b/src/zenserver/hub/zenhubserver.cpp
@@ -36,6 +36,13 @@ ZenHubServerConfigurator::AddCliOptions(cxxopts::Options& Options)
"Instance ID for use in notifications",
cxxopts::value<std::string>(m_ServerOptions.InstanceId)->default_value(""),
"");
+
+ Options.add_option("hub",
+ "",
+ "consul-endpoint",
+ "Consul endpoint URL for service registration (empty = disabled)",
+ cxxopts::value<std::string>(m_ServerOptions.ConsulEndpoint)->default_value(""),
+ "");
}
void
@@ -97,6 +104,9 @@ ZenHubServer::Initialize(const ZenHubServerConfig& ServerConfig, ZenServerState:
InitializeServices(ServerConfig);
RegisterServices(ServerConfig);
+ // Initialize Consul registration after services are set up (REQ-F-12: non-blocking, failure tolerant)
+ InitializeConsulRegistration(ServerConfig, EffectiveBasePort);
+
ZenServerBase::Finalize();
return EffectiveBasePort;
@@ -109,6 +119,10 @@ ZenHubServer::Cleanup()
ZEN_INFO(ZEN_APP_NAME " cleaning up");
try
{
+ // Deregister from Consul first (destructor triggers deregistration)
+ m_ConsulRegistration.reset();
+ m_ConsulClient.reset();
+
m_IoContext.stop();
if (m_IoRunner.joinable())
{
@@ -162,6 +176,47 @@ ZenHubServer::RegisterServices(const ZenHubServerConfig& ServerConfig)
}
void
+ZenHubServer::InitializeConsulRegistration(const ZenHubServerConfig& ServerConfig, int EffectivePort)
+{
+ if (ServerConfig.ConsulEndpoint.empty())
+ {
+ ZEN_INFO("Consul registration disabled (no endpoint configured)");
+ return;
+ }
+
+ ZEN_INFO("Initializing Consul registration with endpoint: {}", ServerConfig.ConsulEndpoint);
+
+ try
+ {
+ m_ConsulClient = std::make_unique<consul::ConsulClient>(ServerConfig.ConsulEndpoint);
+
+ consul::ServiceRegistrationInfo Info;
+ Info.ServiceId = fmt::format("zen-hub-{}", ServerConfig.InstanceId);
+ Info.ServiceName = "zen-hub";
+ Info.Address = "localhost";
+ Info.Port = static_cast<uint16_t>(EffectivePort);
+ Info.HealthEndpoint = "hub/health";
+
+ m_ConsulRegistration = std::make_unique<consul::ServiceRegistration>(m_ConsulClient.get(), Info);
+
+ // Pass Consul client to hub service for child registration
+ if (m_HubService)
+ {
+ m_HubService->SetConsulClient(m_ConsulClient.get());
+ }
+
+ ZEN_INFO("Consul service registration initiated for service ID: {}", Info.ServiceId);
+ }
+ catch (const std::exception& Ex)
+ {
+ // REQ-F-12: Hub should start successfully even if Consul registration fails
+ ZEN_WARN("Failed to initialize Consul registration (hub will continue without it): {}", Ex.what());
+ m_ConsulRegistration.reset();
+ m_ConsulClient.reset();
+ }
+}
+
+void
ZenHubServer::Run()
{
if (m_ProcessMonitor.IsActive())
diff --git a/src/zenserver/hub/zenhubserver.h b/src/zenserver/hub/zenhubserver.h
index ac14362f0..435d8d248 100644
--- a/src/zenserver/hub/zenhubserver.h
+++ b/src/zenserver/hub/zenhubserver.h
@@ -4,6 +4,8 @@
#include "zenserver.h"
+#include <zenutil/consul.h>
+
namespace cxxopts {
class Options;
}
@@ -19,7 +21,8 @@ class HttpHubService;
struct ZenHubServerConfig : public ZenServerConfig
{
std::string UpstreamNotificationEndpoint;
- std::string InstanceId; // For use in notifications
+ std::string InstanceId; // For use in notifications
+ std::string ConsulEndpoint; // If set, enables Consul service registration
};
struct ZenHubServerConfigurator : public ZenServerConfiguratorBase
@@ -84,9 +87,13 @@ private:
std::unique_ptr<HttpHubService> m_HubService;
std::unique_ptr<HttpApiService> m_ApiService;
+ std::unique_ptr<consul::ConsulClient> m_ConsulClient;
+ std::unique_ptr<consul::ServiceRegistration> m_ConsulRegistration;
+
void InitializeState(const ZenHubServerConfig& ServerConfig);
void InitializeServices(const ZenHubServerConfig& ServerConfig);
void RegisterServices(const ZenHubServerConfig& ServerConfig);
+ void InitializeConsulRegistration(const ZenHubServerConfig& ServerConfig, int EffectivePort);
};
} // namespace zen