aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver/hub/zenhubserver.h
blob: d1add7690d3f9c5041ad2331f6bd7a3279f33b39 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "hubinstancestate.h"
#include "resourcemetrics.h"
#include "zenserver.h"

#include <zenutil/consul.h>

namespace cxxopts {
class Options;
}
namespace zen::LuaConfig {
struct Options;
}

namespace zen {

class HttpApiService;
class HttpFrontendService;
class HttpHubService;
class HttpProxyHandler;

struct ZenHubWatchdogConfig
{
	uint32_t CycleIntervalMs					 = 3000;
	uint32_t CycleProcessingBudgetMs			 = 500;
	uint32_t InstanceCheckThrottleMs			 = 5;
	uint32_t ProvisionedInactivityTimeoutSeconds = 600;
	uint32_t HibernatedInactivityTimeoutSeconds	 = 1800;
	uint32_t InactivityCheckMarginSeconds		 = 60;	// Activity check is triggered this far before the inactivity timeout
	uint32_t ActivityCheckConnectTimeoutMs		 = 100;
	uint32_t ActivityCheckRequestTimeoutMs		 = 200;
};

struct ZenHubServerConfig : public ZenServerConfig
{
	std::string			  UpstreamNotificationEndpoint;
	std::string			  InstanceId;	   // For use in notifications
	std::string			  ConsulEndpoint;  // If set, enables Consul service registration
	std::string			  ConsulTokenEnv;  // Environment variable name to read a Consul token from; defaults to CONSUL_HTTP_TOKEN if empty
	uint32_t			  ConsulHealthIntervalSeconds  = 10;  // Interval in seconds between Consul health checks
	uint32_t			  ConsulDeregisterAfterSeconds = 30;  // Seconds before Consul deregisters an unhealthy service
	uint16_t			  HubBasePortNumber			   = 21000;
	int					  HubInstanceLimit			   = 1000;
	bool				  HubUseJobObject			   = true;
	std::string			  HubInstanceHttpClass		   = "asio";
	uint32_t			  HubInstanceHttpThreadCount   = 0;	 // Automatic
	int					  HubInstanceCoreLimit		   = 0;	 // Automatic
	std::filesystem::path HubInstanceConfigPath;			 // Path to Lua config file
	std::string			  HydrationTargetSpecification;		 // hydration/dehydration target specification
	std::filesystem::path HydrationTargetConfigPath;  // path to JSON config file (mutually exclusive with HydrationTargetSpecification)
	ZenHubWatchdogConfig  WatchdogConfig;
	uint64_t			  HubProvisionDiskLimitBytes	 = 0;
	uint32_t			  HubProvisionDiskLimitPercent	 = 0;
	uint64_t			  HubProvisionMemoryLimitBytes	 = 0;
	uint32_t			  HubProvisionMemoryLimitPercent = 0;
};

class Hub;
struct HubProvisionedInstanceInfo;

struct ZenHubServerConfigurator : public ZenServerConfiguratorBase
{
	ZenHubServerConfigurator(ZenHubServerConfig& ServerOptions) : ZenServerConfiguratorBase(ServerOptions), m_ServerOptions(ServerOptions)
	{
	}

	~ZenHubServerConfigurator() = default;

private:
	virtual void AddCliOptions(cxxopts::Options& Options) override;
	virtual void AddConfigOptions(LuaConfig::Options& Options) override;
	virtual void ApplyOptions(cxxopts::Options& Options) override;
	virtual void OnConfigFileParsed(LuaConfig::Options& LuaOptions) override;
	virtual void ValidateOptions() override;

	ZenHubServerConfig& m_ServerOptions;
};

class ZenHubServerMain : public ZenServerMain
{
public:
	ZenHubServerMain(ZenHubServerConfig& ServerOptions);
	virtual void DoRun(ZenServerState::ZenServerEntry* Entry) override;

	ZenHubServerMain(const ZenHubServerMain&) = delete;
	ZenHubServerMain& operator=(const ZenHubServerMain&) = delete;

	typedef ZenHubServerConfig		 Config;
	typedef ZenHubServerConfigurator Configurator;

private:
	ZenHubServerConfig& m_ServerOptions;
};

class ZenHubServer : public ZenServerBase
{
	ZenHubServer& operator=(ZenHubServer&&) = delete;
	ZenHubServer(ZenHubServer&&)			= delete;

public:
	ZenHubServer();
	~ZenHubServer();

	int	 Initialize(const ZenHubServerConfig& ServerConfig, ZenServerState::ZenServerEntry* ServerEntry);
	void Run();
	void Cleanup();

	void SetDataRoot(std::filesystem::path Root) { m_DataRoot = Root; }
	void SetContentRoot(std::filesystem::path Root) { m_ContentRoot = Root; }

private:
	void OnModuleStateChanged(std::string_view					HubInstanceId,
							  std::string_view					ModuleId,
							  const HubProvisionedInstanceInfo& Info,
							  HubInstanceState					PreviousState,
							  HubInstanceState					NewState);

	std::filesystem::path m_DataRoot;
	std::filesystem::path m_ContentRoot;
	bool				  m_DebugOptionForcedCrash = false;

	std::unique_ptr<HttpProxyHandler> m_Proxy;
	std::unique_ptr<Hub>			  m_Hub;

	std::unique_ptr<HttpHubService>		 m_HubService;
	std::unique_ptr<HttpApiService>		 m_ApiService;
	std::unique_ptr<HttpFrontendService> m_FrontendService;

	std::unique_ptr<consul::ConsulClient>		 m_ConsulClient;
	std::unique_ptr<consul::ServiceRegistration> m_ConsulRegistration;
	uint32_t									 m_ConsulHealthIntervalSeconds	= 10;
	uint32_t									 m_ConsulDeregisterAfterSeconds = 30;

	static ResourceMetrics ResolveLimits(const ZenHubServerConfig& ServerConfig);

	void InitializeState(const ZenHubServerConfig& ServerConfig);
	void InitializeServices(const ZenHubServerConfig& ServerConfig);
	void RegisterServices(const ZenHubServerConfig& ServerConfig);
	void InitializeConsulRegistration(const ZenHubServerConfig& ServerConfig, int EffectivePort);
};

}  // namespace zen