agent_process.py 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import os
  2. import sys
  3. import json
  4. import time
  5. import signal
  6. import subprocess
  7. from typing import Any, Dict, Optional
  8. PID_FILE = os.path.join(os.path.dirname(__file__), 'agent_scheduler.pid')
  9. def _write_pid_file(pid: int) -> None:
  10. with open(PID_FILE, 'w') as f:
  11. f.write(str(pid))
  12. def _read_pid_file() -> Optional[int]:
  13. if not os.path.exists(PID_FILE):
  14. return None
  15. try:
  16. with open(PID_FILE, 'r') as f:
  17. content = f.read().strip()
  18. return int(content) if content else None
  19. except Exception:
  20. return None
  21. def _is_process_running(pid: int) -> bool:
  22. try:
  23. os.kill(pid, 0)
  24. return True
  25. except Exception:
  26. return False
  27. def start_daemon(host: str, port: int) -> Dict[str, Any]:
  28. old_pid = _read_pid_file()
  29. if old_pid and _is_process_running(old_pid):
  30. return {"status": "already_running", "pid": old_pid}
  31. python_exec = sys.executable
  32. script_path = os.path.join(os.path.dirname(__file__), 'agent.py')
  33. args = [python_exec, script_path, "--serve", "--host", host, "--port", str(port)]
  34. with open(os.devnull, 'wb') as devnull:
  35. proc = subprocess.Popen(
  36. args,
  37. stdout=devnull,
  38. stderr=devnull,
  39. stdin=devnull,
  40. close_fds=True,
  41. preexec_fn=os.setsid if hasattr(os, 'setsid') else None,
  42. )
  43. _write_pid_file(proc.pid)
  44. time.sleep(0.5)
  45. running = _is_process_running(proc.pid)
  46. return {"status": "started" if running else "failed", "pid": proc.pid}
  47. def stop_daemon(timeout: float = 5.0) -> Dict[str, Any]:
  48. pid = _read_pid_file()
  49. if not pid:
  50. return {"status": "not_running"}
  51. if not _is_process_running(pid):
  52. try:
  53. os.remove(PID_FILE)
  54. except Exception:
  55. pass
  56. return {"status": "not_running"}
  57. try:
  58. os.kill(pid, signal.SIGTERM)
  59. except Exception as e:
  60. return {"status": "error", "error": str(e)}
  61. start_time = time.time()
  62. while time.time() - start_time < timeout:
  63. if not _is_process_running(pid):
  64. break
  65. time.sleep(0.2)
  66. if _is_process_running(pid):
  67. try:
  68. os.kill(pid, signal.SIGKILL)
  69. except Exception as e:
  70. return {"status": "error", "error": str(e)}
  71. try:
  72. os.remove(PID_FILE)
  73. except Exception:
  74. pass
  75. return {"status": "stopped"}
  76. def status_daemon() -> Dict[str, Any]:
  77. pid = _read_pid_file()
  78. if pid and _is_process_running(pid):
  79. return {"status": "running", "pid": pid}
  80. return {"status": "not_running"}