Keep FastCGI available during restarts

This commit is contained in:
udo
2026-07-16 22:00:08 +00:00
parent 93c701c6c7
commit caffb3f404
16 changed files with 192 additions and 41 deletions
+57 -13
View File
@@ -699,15 +699,7 @@ volatile bool termination_signal_received = false;
void on_terminate(int sig)
{
if(termination_signal_received)
return;
termination_signal_received = true;
if(getpid() != parent_pid)
exit(1);
printf("Terminating... PID %i:%i\n", getpid(), parent_pid);
wasm_backend_shutdown();
server.shutdown();
exit(1);
}
void clear_shared_unit_cache(ServerState& state)
@@ -1069,7 +1061,7 @@ void run_ws_broker()
ws_broker.listen(server_state.config["WS_BROKER_SOCKET_PATH"]);
chmod(server_state.config["WS_BROKER_SOCKET_PATH"].c_str(), S_IRWXU | S_IRGRP | S_IWGRP);
}
for(;;)
while(!termination_signal_received)
{
ws_broker.process(50);
ws_broker_drain_outbound(ws_broker_outbound_timeout_seconds);
@@ -1254,7 +1246,7 @@ void run_proactive_compiler()
}
next_scan_at = time_precise();
for(;;)
while(!termination_signal_received)
{
try
{
@@ -1397,10 +1389,21 @@ void listen_for_connections()
printf("(P) wasm worker ready: PID %i in %.3f ms\n", getpid(), wasm_ms);
else
fprintf(stderr, "(!) wasm worker initialization failed: PID %i in %.3f ms: %s\n", getpid(), wasm_ms, wasm_error.c_str());
for(;;)
while(!termination_signal_received)
{
server.process(-1);
}
close_inherited_server_sockets();
f64 drain_deadline = time_precise() + (f64)to_u64(server_state.config["WORKER_DRAIN_TIMEOUT_SECONDS"], 10);
while(!server.client_sockets.empty() && time_precise() < drain_deadline)
server.process(100);
if(!server.client_sockets.empty())
fprintf(stderr, "(!) worker PID %i drain deadline reached with %zu client connections\n",
getpid(), server.client_sockets.size());
else
printf("(P) worker PID %i drained cleanly\n", getpid());
wasm_backend_shutdown();
exit(server.client_sockets.empty() ? 0 : 1);
}
mode_t configured_socket_mode(String value, mode_t fallback)
@@ -1424,6 +1427,25 @@ void chmod_configured_socket(String path, String mode_value, mode_t fallback)
fprintf(stderr, "(!) Could not chmod socket %s to %04o: %s\n", path.c_str(), (unsigned int)mode, strerror(errno));
}
int systemd_fastcgi_listener()
{
const char* listen_pid = getenv("LISTEN_PID");
const char* listen_fds = getenv("LISTEN_FDS");
if(!listen_pid || !listen_fds)
return(-1);
if(to_u64(listen_pid, 0) != (u64)getpid())
return(-1);
if(to_u64(listen_fds, 0) != 1)
throw std::runtime_error("UCE requires exactly one systemd FastCGI listener");
const char* names = getenv("LISTEN_FDNAMES");
if(names && names[0] != '\0' && String(names) != "fastcgi")
throw std::runtime_error("systemd listener must be named fastcgi");
unsetenv("LISTEN_PID");
unsetenv("LISTEN_FDS");
unsetenv("LISTEN_FDNAMES");
return(3);
}
StringMap redacted_server_config_for_log(const StringMap& config)
{
StringMap redacted = config;
@@ -1443,13 +1465,16 @@ void init_base_process()
server_state.config = make_server_settings();
server_state.config["COMPILER_SYS_PATH"] = cwd_get();
printf("Compiler base path: %s\n", server_state.config["COMPILER_SYS_PATH"].c_str());
int inherited_fastcgi = systemd_fastcgi_listener();
if(inherited_fastcgi >= 0)
server.adopt_listener(inherited_fastcgi, 'F');
if(server_state.config["FCGI_PORT"] != "")
server.listen(int_val(server_state.config["FCGI_PORT"]));
printf("%s\n", var_dump(redacted_server_config_for_log(server_state.config)).c_str());
if(server_state.config["FCGI_SOCKET_PATH"] != "")
if(inherited_fastcgi < 0 && server_state.config["FCGI_SOCKET_PATH"] != "")
{
server.listen(server_state.config["FCGI_SOCKET_PATH"]);
chmod_configured_socket(server_state.config["FCGI_SOCKET_PATH"], server_state.config["FCGI_SOCKET_MODE"], 0666);
@@ -1469,7 +1494,9 @@ void init_base_process()
mkdir(server_state.config["SESSION_PATH"]);
signal(SIGCHLD, on_child_exit);
signal(SIGTERM, on_terminate);
signal(SIGINT, on_terminate);
signal(SIGHUP, on_terminate);
signal(SIGPIPE, SIG_IGN);
srand(time());
}
@@ -1489,7 +1516,7 @@ int main(int argc, char** argv)
ensure_proactive_compiler();
ensure_ws_broker();
for(;;)
while(!termination_signal_received)
{
if(!proactive_compiler_alive())
proactive_compiler_pid = 0;
@@ -1512,5 +1539,22 @@ int main(int argc, char** argv)
sleep(1);
}
printf("(P) draining %zu workers before shutdown\n", workers.size());
for(auto& worker : workers)
kill(worker.first, SIGTERM);
if(proactive_compiler_pid > 0)
kill(proactive_compiler_pid, SIGTERM);
if(ws_broker_pid > 0)
kill(ws_broker_pid, SIGTERM);
f64 drain_deadline = time_precise() + (f64)to_u64(server_state.config["WORKER_DRAIN_TIMEOUT_SECONDS"], 10);
while(!workers.empty() && time_precise() < drain_deadline)
{
on_child_exit(0);
usleep(10000);
}
for(auto& worker : workers)
kill(worker.first, SIGKILL);
server.shutdown();
return 0;
}