138 lines
5.2 KiB
Python
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)
|