81 lines
2.5 KiB
Python
Executable File
81 lines
2.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Uruchamia komendę w tle, odczepioną od bieżącej sesji terminala.
|
|
|
|
Powód istnienia: `nohup ... &` wewnątrz zadania go-task nie wystarcza - interpreter
|
|
zadania kończy się razem z krokiem i zabija potomka. `start_new_session=True` robi
|
|
to, co `setsid` na Linuksie, a działa też na macOS, gdzie `setsid` nie istnieje.
|
|
|
|
Użycie:
|
|
daemonize.py --pidfile .runs/llm/mock.pid --log .runs/llm/mock.log -- python3 llm/mock_server.py
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import os
|
|
import signal
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
def already_running(pidfile: Path) -> int | None:
|
|
if not pidfile.exists():
|
|
return None
|
|
try:
|
|
pid = int(pidfile.read_text().strip())
|
|
os.kill(pid, 0)
|
|
except (ValueError, ProcessLookupError, PermissionError, OSError):
|
|
return None
|
|
return pid
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
parser.add_argument("--pidfile", required=True)
|
|
parser.add_argument("--log", required=True)
|
|
parser.add_argument("--stop", action="store_true", help="zatrzymaj proces z pidfile zamiast startować")
|
|
parser.add_argument("command", nargs=argparse.REMAINDER)
|
|
args = parser.parse_args()
|
|
|
|
pidfile = Path(args.pidfile)
|
|
pidfile.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
if args.stop:
|
|
pid = already_running(pidfile)
|
|
if pid is None:
|
|
print(f"nic nie działa pod {pidfile}")
|
|
pidfile.unlink(missing_ok=True)
|
|
return 0
|
|
os.kill(pid, signal.SIGTERM)
|
|
pidfile.unlink(missing_ok=True)
|
|
print(f"zatrzymano pid {pid}")
|
|
return 0
|
|
|
|
command = [arg for arg in args.command if arg != "--"]
|
|
if not command:
|
|
parser.error("podaj komendę do uruchomienia po --")
|
|
|
|
running = already_running(pidfile)
|
|
if running is not None:
|
|
print(f"już działa (pid {running})")
|
|
return 0
|
|
|
|
log = Path(args.log)
|
|
log.parent.mkdir(parents=True, exist_ok=True)
|
|
with log.open("ab") as handle:
|
|
process = subprocess.Popen(
|
|
command,
|
|
stdout=handle,
|
|
stderr=subprocess.STDOUT,
|
|
stdin=subprocess.DEVNULL,
|
|
start_new_session=True, # odpowiednik setsid, przenośny między Linuksem a macOS
|
|
)
|
|
pidfile.write_text(str(process.pid))
|
|
print(f"uruchomiono pid {process.pid} (log: {log})")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|