diff options
| author | Stefan Boberg <[email protected]> | 2023-06-16 14:42:34 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-06-16 14:42:34 +0200 |
| commit | bd569bcfb4b249cded1cc68caddabcdc2db9b223 (patch) | |
| tree | bc442a01b9f98848afeaf6bcfbe5a0c29987008d /src | |
| parent | make sure to set error code to zero on success (diff) | |
| download | zen-bd569bcfb4b249cded1cc68caddabcdc2db9b223.tar.xz zen-bd569bcfb4b249cded1cc68caddabcdc2db9b223.zip | |
added ZenServerInstance::SpawnServerAndWait (#334)
this change adds `ZenServerInstance::SpawnServerAndWait()` which as the name implies spawns a server and then waits for the instance to reach a usable state before returning to the caller.
It also changes the behaviour of `ZenServerInstance::AttachToRunningServer()` so it matches the Spawn behaviour wrt automatic termination on ZenServerInstance destruction. Previously it would always terminate the subprocess on exit.
Diffstat (limited to 'src')
| -rw-r--r-- | src/zenutil/include/zenutil/zenserverprocess.h | 16 | ||||
| -rw-r--r-- | src/zenutil/zenserverprocess.cpp | 52 |
2 files changed, 62 insertions, 6 deletions
diff --git a/src/zenutil/include/zenutil/zenserverprocess.h b/src/zenutil/include/zenutil/zenserverprocess.h index a0a705f64..7b78261bc 100644 --- a/src/zenutil/include/zenutil/zenserverprocess.h +++ b/src/zenutil/include/zenutil/zenserverprocess.h @@ -58,6 +58,7 @@ struct ZenServerInstance void WaitUntilReady(); [[nodiscard]] bool WaitUntilReady(int Timeout); void EnableTermination() { m_Terminate = true; } + void DisableShutdownOnDestroy() { m_ShutdownOnDestroy = false; } void Detach(); inline int GetPid() { return m_Process.Pid(); } inline void SetOwnerPid(int Pid) { m_OwnerPid = Pid; } @@ -68,7 +69,16 @@ struct ZenServerInstance m_TestDir = TestDir; } - void SpawnServer(int BasePort = 0, std::string_view AdditionalServerArgs = std::string_view()); + inline void SpawnServer(int BasePort = 0, std::string_view AdditionalServerArgs = std::string_view()) + { + SpawnServer(BasePort, AdditionalServerArgs, /* WaitTimeoutMs */ 0); + } + + inline void SpawnServerAndWait(int BasePort = 0, std::string_view AdditionalServerArgs = std::string_view(), int WaitTimeoutMs = 10000) + { + SpawnServer(BasePort, AdditionalServerArgs, WaitTimeoutMs); + } + void AttachToRunningServer(int BasePort = 0); std::string GetBaseUri() const; @@ -77,12 +87,14 @@ private: ProcessHandle m_Process; NamedEvent m_ReadyEvent; NamedEvent m_ShutdownEvent; - bool m_Terminate = false; + bool m_Terminate = false; + bool m_ShutdownOnDestroy = true; std::filesystem::path m_TestDir; int m_BasePort = 0; std::optional<int> m_OwnerPid; void CreateShutdownEvent(int BasePort); + void SpawnServer(int BasePort, std::string_view AdditionalServerArgs, int WaitTimeoutMs); }; /** Shared Zen system state diff --git a/src/zenutil/zenserverprocess.cpp b/src/zenutil/zenserverprocess.cpp index ead919cb9..d1a91b93f 100644 --- a/src/zenutil/zenserverprocess.cpp +++ b/src/zenutil/zenserverprocess.cpp @@ -476,7 +476,7 @@ ZenServerInstance::SignalShutdown() void ZenServerInstance::Shutdown() { - if (m_Process.IsValid()) + if (m_Process.IsValid() && m_ShutdownOnDestroy) { if (m_Terminate) { @@ -494,7 +494,7 @@ ZenServerInstance::Shutdown() } void -ZenServerInstance::SpawnServer(int BasePort, std::string_view AdditionalServerArgs) +ZenServerInstance::SpawnServer(int BasePort, std::string_view AdditionalServerArgs, int WaitTimeoutMs) { ZEN_ASSERT(!m_Process.IsValid()); // Only spawn once @@ -587,12 +587,55 @@ ZenServerInstance::SpawnServer(int BasePort, std::string_view AdditionalServerAr ZEN_DEBUG("Server '{}' spawned OK", LogId); - if (IsTest) + m_Process.Initialize(ChildPid); + + if (IsTest == false) { - m_Process.Initialize(ChildPid); + DisableShutdownOnDestroy(); } m_ReadyEvent = std::move(ChildEvent); + + if (WaitTimeoutMs) + { + if (!WaitUntilReady(WaitTimeoutMs)) + { + throw std::runtime_error(fmt::format("server start timeout after {}", NiceTimeSpanMs(WaitTimeoutMs))); + } + + // Determine effective base port + + ZenServerState State; + if (!State.InitializeReadOnly()) + { + // TODO: return success/error code instead? + throw std::runtime_error("no zen state found"); + } + + const ZenServerState::ZenServerEntry* Entry = nullptr; + + if (BasePort) + { + Entry = State.Lookup(BasePort); + } + else + { + State.Snapshot([&](const ZenServerState::ZenServerEntry& InEntry) { + if (InEntry.Pid == static_cast<uint32_t>(GetProcessId(ChildPid))) + { + Entry = &InEntry; + } + }); + } + + if (!Entry) + { + // TODO: return success/error code instead? + throw std::runtime_error("no server entry found"); + } + + m_BasePort = Entry->EffectiveListenPort; + } } void @@ -634,6 +677,7 @@ ZenServerInstance::AttachToRunningServer(int BasePort) m_Process.Initialize(Entry->Pid); CreateShutdownEvent(Entry->EffectiveListenPort); + m_BasePort = Entry->EffectiveListenPort; } void |