phase0: archive Python implementation under archive/
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
GRACEFUL_TIMEOUT_SECONDS = 10
|
||||
|
||||
|
||||
def build_processes() -> list[subprocess.Popen[bytes]]:
|
||||
root = Path(__file__).resolve().parent
|
||||
return [
|
||||
subprocess.Popen(
|
||||
[
|
||||
sys.executable,
|
||||
"-m",
|
||||
"uvicorn",
|
||||
"app.api:app",
|
||||
"--host",
|
||||
"0.0.0.0",
|
||||
"--port",
|
||||
"8000",
|
||||
],
|
||||
cwd=root,
|
||||
),
|
||||
subprocess.Popen(
|
||||
[
|
||||
sys.executable,
|
||||
"-m",
|
||||
"streamlit",
|
||||
"run",
|
||||
"app/streamlit_app.py",
|
||||
"--server.port",
|
||||
"8501",
|
||||
"--server.address",
|
||||
"0.0.0.0",
|
||||
"--server.headless",
|
||||
"true",
|
||||
"--browser.gatherUsageStats",
|
||||
"false",
|
||||
],
|
||||
cwd=root,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def stop_processes(processes: list[subprocess.Popen[bytes]], skip_pid: int | None = None) -> None:
|
||||
for process in processes:
|
||||
if process.pid == skip_pid:
|
||||
continue
|
||||
if process.poll() is None:
|
||||
process.terminate()
|
||||
|
||||
|
||||
def reap_processes(
|
||||
processes: list[subprocess.Popen[bytes]], skip_pid: int | None = None
|
||||
) -> None:
|
||||
for process in processes:
|
||||
if process.pid == skip_pid:
|
||||
continue
|
||||
if process.poll() is not None:
|
||||
continue
|
||||
try:
|
||||
process.wait(timeout=GRACEFUL_TIMEOUT_SECONDS)
|
||||
except subprocess.TimeoutExpired:
|
||||
process.kill()
|
||||
process.wait()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
processes = build_processes()
|
||||
exit_code = 0
|
||||
shutting_down = False
|
||||
|
||||
def handle_signal(signum, _frame) -> None:
|
||||
nonlocal exit_code, shutting_down
|
||||
if shutting_down:
|
||||
return
|
||||
shutting_down = True
|
||||
exit_code = 128 + signum
|
||||
stop_processes(processes)
|
||||
|
||||
signal.signal(signal.SIGTERM, handle_signal)
|
||||
signal.signal(signal.SIGINT, handle_signal)
|
||||
|
||||
while True:
|
||||
try:
|
||||
pid, status = os_wait()
|
||||
except ChildProcessError:
|
||||
break
|
||||
except InterruptedError:
|
||||
continue
|
||||
|
||||
process = next((item for item in processes if item.pid == pid), None)
|
||||
if process is not None:
|
||||
process.returncode = os_waitstatus_to_exitcode(status)
|
||||
|
||||
if not shutting_down:
|
||||
exit_code = os_waitstatus_to_exitcode(status)
|
||||
shutting_down = True
|
||||
stop_processes(processes, skip_pid=pid)
|
||||
|
||||
reap_processes(processes, skip_pid=pid)
|
||||
break
|
||||
|
||||
reap_processes(processes)
|
||||
return exit_code
|
||||
|
||||
|
||||
def os_wait() -> tuple[int, int]:
|
||||
import os
|
||||
|
||||
return os.wait()
|
||||
|
||||
|
||||
def os_waitstatus_to_exitcode(status: int) -> int:
|
||||
import os
|
||||
|
||||
return os.waitstatus_to_exitcode(status)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user