Files
2026-08-29 13:17:59 +02:00

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