python_script_manager/service.py
2026-03-07 12:56:09 +03:00

111 lines
2.3 KiB
Python

import os
import signal
import sys
import textwrap
import time
from pathlib import Path
PID_FILE = Path("pid.txt")
MAIN_SCRIPT = "main.py"
START_DELAY = 0.3
def display_help():
print(
textwrap.dedent("""\
Usage: python service.py <option>
Options:
status - Get status of main script.
start - Start main script.
stop - Stop main script.
restart - Restart main script.""")
)
def get_pid() -> int | None:
try:
content = PID_FILE.read_text().strip()
pid = int(content)
# Verify the process actually exists
os.kill(pid, 0)
return pid
except (FileNotFoundError, ValueError, ProcessLookupError, PermissionError):
return None
def clear_pid():
PID_FILE.write_text("")
def start_process():
os.system(f"nohup python {MAIN_SCRIPT} &")
time.sleep(START_DELAY)
return get_pid()
def cmd_status():
pid = get_pid()
if pid:
print(f"[Running] PID: {pid}")
return 0
print("[Stopped]")
return 1
def cmd_start():
if pid := get_pid():
print(f"Already running with PID: {pid}")
return 2
if pid := start_process():
print(f"Started with PID: {pid}")
return 0
print(f"Can't get PID... Crash? | CWD: {os.getcwd()}")
return 1
def cmd_stop():
pid = get_pid()
clear_pid()
if not pid:
print(f"Process already stopped. | CWD: {os.getcwd()}")
return 2
try:
os.kill(pid, signal.SIGTERM) # Graceful shutdown vs SIGKILL
print("Process successfully stopped.")
return 0
except ProcessLookupError:
print(f"Process already stopped. | CWD: {os.getcwd()}")
return 2
def cmd_restart():
pid = get_pid()
if pid:
try:
os.kill(pid, signal.SIGTERM)
except ProcessLookupError:
pass
clear_pid()
if pid := start_process():
print(f"Restarted with PID: {pid}")
return 0
print(f"Can't get PID... Crash? | CWD: {os.getcwd()}")
return 1
COMMANDS = {
"status": cmd_status,
"start": cmd_start,
"stop": cmd_stop,
"restart": cmd_restart,
}
if __name__ == "__main__":
if len(sys.argv) < 2 or sys.argv[1] not in COMMANDS:
display_help()
sys.exit(0)
exit_code = COMMANDS[sys.argv[1]]()
sys.exit(exit_code)