ARC_Starter/backend/watchdog.py

138 lines
5.2 KiB
Python

import subprocess
import threading
import time
import pymysql
import logging
import configparser
import psutil
CONFIG_PATH = "/app/config.ini"
config = configparser.ConfigParser()
config.read(CONFIG_PATH)
loglevel_str = config["log"]["level"].upper()
loglevel = getattr(logging, loglevel_str, logging.INFO)
logging.basicConfig(level=loglevel)
DB_CONFIG = {
'host': config["database"]["host"],
'user': config["database"]["user"],
'password': config["database"]["password"],
'database': config["database"]["database"]
}
running_services = {}
def get_process_on_port(port):
for conn in psutil.net_connections(kind='inet'):
if conn.laddr.port == port and conn.status == psutil.CONN_LISTEN:
pid = conn.pid
if pid is None:
continue
try:
proc = psutil.Process(pid)
return {
'pid': pid,
'name': proc.name(),
'cmdline': proc.cmdline()
}
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
return None
def initialize_running_services_from_db(db_config):
try:
conn = pymysql.connect(**db_config)
cursor = conn.cursor(pymysql.cursors.DictCursor)
cursor.execute("SELECT name, tcpport FROM receivers;")
rows = cursor.fetchall()
for row in rows:
name = row['name']
port = row['tcpport']
proc_info = get_process_on_port(port)
if proc_info:
logging.info(f"[INIT] Found existing service '{name}' on port {port}, PID={proc_info['pid']}, Cmd={proc_info['cmdline']}")
running_services[name] = {
"pid": proc_info["pid"],
"cmdline": proc_info["cmdline"]
}
cursor.close()
conn.close()
except Exception as e:
logging.exception("[INIT] Failed to detect existing services")
def watchdog(db_config):
global running_services
while True:
try:
thread_conn = pymysql.connect(**db_config)
cursor = thread_conn.cursor(pymysql.cursors.DictCursor)
cursor.execute("SELECT name, type, tcpport, enabled FROM receivers;")
rows = cursor.fetchall()
cursor.close()
thread_conn.close()
for row in rows:
name = row["name"]
receiver_type = row["type"]
port = row["tcpport"]
enabled = row["enabled"]
if receiver_type != "SIA-DC09":
continue
if enabled == 1 and name not in running_services:
binary_path = "/app/tcp_sia_server.bin"
logging.info(f"[WATCHDOG] Starting receiver '{name}' on port {port}")
start_service(name, binary_path, port)
elif enabled == 0:
proc_info = running_services.get(name)
if proc_info and isinstance(proc_info, subprocess.Popen):
logging.info(f"[WATCHDOG] Stopping disabled receiver '{name}' (started by script)")
proc_info.terminate()
proc_info.wait()
del running_services[name]
else:
# Kill external process using psutil
port = row["tcpport"]
try:
for conn in psutil.net_connections(kind='inet'):
if conn.laddr.port == port and conn.status == psutil.CONN_LISTEN:
pid = conn.pid
if pid:
logging.warning(
f"[WATCHDOG] Force killing external process on port {port} (PID {pid}) for receiver '{name}'")
psutil.Process(pid).kill()
if name in running_services:
del running_services[name]
except Exception as e:
logging.exception(f"[WATCHDOG] Failed to kill external process for receiver '{name}'")
log_thread_status()
time.sleep(3)
except Exception as e:
logging.exception(f"[WATCHDOG] Error during check: {e}")
def start_service(name, binary_path, port=None):
def run():
cmd = [binary_path]
if port:
cmd.append(str(port))
logging.info(f"[WATCHDOG] Starting {name} on port {port}...")
process = subprocess.Popen(cmd)
running_services[name] = {
"popen": process
}
process.wait()
logging.warning(f"[WATCHDOG] {name} exited.")
thread = threading.Thread(target=run, daemon=True)
thread.start()
def log_thread_status():
running = list(running_services.keys())
logging.debug(f"[STATUS] Running services: {running if running else 'None'}")
if __name__ == "__main__":
initialize_running_services_from_db(DB_CONFIG)
logging.debug(f"[INIT] Active running_services: {list(running_services.keys())}")
watchdog(DB_CONFIG)