mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-29 07:05:14 -07:00
fix: reliably keep server alive after GUI close on Windows (#402)
The HTTP /watchdog/disable request races with process exit on Windows, causing the watchdog to kill the server before the request arrives. Added a .keep-running sentinel file as a reliable fallback: - Tauri writes the file to data_dir before sending the HTTP request - The watchdog checks for it during the grace period after detecting parent death - The file is removed after being read to avoid stale state This approach works regardless of HTTP timing because file writes complete synchronously before the Tauri process exits. Fixes #372 Co-authored-by: Matt Van Horn <[email protected]>
This commit is contained in:
co-authored by
Matt Van Horn
parent
3e7727d1d2
commit
479bc7fc5e
@@ -105,6 +105,11 @@ def _start_parent_watchdog(parent_pid, data_dir=None):
|
|||||||
This is the clean shutdown mechanism: instead of the Tauri app trying to
|
This is the clean shutdown mechanism: instead of the Tauri app trying to
|
||||||
forcefully kill the server (which spawns console windows on Windows),
|
forcefully kill the server (which spawns console windows on Windows),
|
||||||
the server monitors its parent and shuts itself down gracefully.
|
the server monitors its parent and shuts itself down gracefully.
|
||||||
|
|
||||||
|
The Tauri app writes a .keep-running sentinel file to data_dir before
|
||||||
|
exiting when "remain running after close" is enabled. This is a reliable
|
||||||
|
fallback for the HTTP /watchdog/disable request, which can race with
|
||||||
|
process exit on Windows.
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import signal
|
import signal
|
||||||
@@ -178,6 +183,18 @@ def _start_parent_watchdog(parent_pid, data_dir=None):
|
|||||||
if _watchdog_disabled:
|
if _watchdog_disabled:
|
||||||
watchdog_logger.info("Watchdog was disabled during grace period, keeping server alive")
|
watchdog_logger.info("Watchdog was disabled during grace period, keeping server alive")
|
||||||
return
|
return
|
||||||
|
# Check for sentinel file written by Tauri before exit.
|
||||||
|
# This catches the case where the HTTP disable request
|
||||||
|
# didn't arrive before the parent process died (common
|
||||||
|
# on Windows where process teardown is fast).
|
||||||
|
sentinel = os.path.join(data_dir, ".keep-running") if data_dir else None
|
||||||
|
if sentinel and os.path.exists(sentinel):
|
||||||
|
watchdog_logger.info("Found .keep-running sentinel file, keeping server alive")
|
||||||
|
try:
|
||||||
|
os.remove(sentinel)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
return
|
||||||
watchdog_logger.info("Watchdog still enabled after grace period, shutting down server...")
|
watchdog_logger.info("Watchdog still enabled after grace period, shutting down server...")
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
# sys.exit triggers SystemExit, allowing uvicorn to run
|
# sys.exit triggers SystemExit, allowing uvicorn to run
|
||||||
|
|||||||
@@ -860,6 +860,22 @@ pub fn run() {
|
|||||||
// Tell the server to disable its watchdog so it survives
|
// Tell the server to disable its watchdog so it survives
|
||||||
// after this process exits.
|
// after this process exits.
|
||||||
println!("Keep server running: disabling watchdog...");
|
println!("Keep server running: disabling watchdog...");
|
||||||
|
|
||||||
|
// Write a sentinel file as a reliable fallback. On Windows
|
||||||
|
// the HTTP request below can race with process exit, leaving
|
||||||
|
// the watchdog unaware it should stay alive. The sentinel
|
||||||
|
// file is checked during the watchdog grace period.
|
||||||
|
let data_dir = app
|
||||||
|
.path()
|
||||||
|
.app_data_dir()
|
||||||
|
.unwrap_or_default();
|
||||||
|
let sentinel = data_dir.join(".keep-running");
|
||||||
|
if let Err(e) = std::fs::write(&sentinel, b"1") {
|
||||||
|
eprintln!("Failed to write keep-running sentinel: {}", e);
|
||||||
|
} else {
|
||||||
|
println!("Wrote keep-running sentinel to {:?}", sentinel);
|
||||||
|
}
|
||||||
|
|
||||||
let client = reqwest::blocking::Client::builder()
|
let client = reqwest::blocking::Client::builder()
|
||||||
.timeout(std::time::Duration::from_secs(2))
|
.timeout(std::time::Duration::from_secs(2))
|
||||||
.build()
|
.build()
|
||||||
|
|||||||
Reference in New Issue
Block a user