Files
md-to-html/start.py
T
Sergey Filkin 0fe596383e Initial commit
2026-04-17 23:39:57 +03:00

123 lines
2.9 KiB
Python

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())