Files

114 lines
3.1 KiB
Python
Raw Permalink Normal View History

import asyncio
import os
import subprocess
import sys
import time
from pathlib import Path
PROJECT = Path(__file__).resolve().parents[1]
PID_FILE = PROJECT / "logs" / "bot.pid"
LOG_FILE = PROJECT / "logs" / "bot_stderr.log"
def _taskkill(pid: int) -> None:
subprocess.run(["taskkill", "/PID", str(pid), "/F"], capture_output=True, text=True)
def _find_bot_pids() -> list[int]:
command = (
"Get-CimInstance Win32_Process | "
"Where-Object { $_.Name -like 'python*' -and "
"($_.CommandLine -like '*app/main.py*' "
"-or $_.CommandLine -like '*app\\\\main.py*') } | "
"Select-Object -ExpandProperty ProcessId"
)
result = subprocess.run(
["powershell", "-NoProfile", "-Command", command],
capture_output=True,
text=True,
)
pids: list[int] = []
for line in result.stdout.splitlines():
line = line.strip()
if line.isdigit():
pids.append(int(line))
return pids
def _kill_existing_bots() -> None:
killed: set[int] = set()
if PID_FILE.exists():
try:
pid = int(PID_FILE.read_text(encoding="utf-8").strip())
_taskkill(pid)
killed.add(pid)
print(f"PID file process stopped: {pid}")
except Exception as exc:
print(f"PID file stop skipped: {exc}")
PID_FILE.unlink(missing_ok=True)
for pid in _find_bot_pids():
if pid in killed:
continue
_taskkill(pid)
killed.add(pid)
print(f"Existing bot process stopped: {pid}")
if not killed:
print("No existing bot process found")
def _start_bot() -> int:
PROJECT.joinpath("logs").mkdir(exist_ok=True)
env = os.environ.copy()
env["PYTHONUNBUFFERED"] = "1"
creationflags = 0
if hasattr(subprocess, "DETACHED_PROCESS"):
creationflags = subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP
with open(LOG_FILE, "a", encoding="utf-8") as log:
proc = subprocess.Popen(
[sys.executable, "-u", "app/main.py"],
cwd=PROJECT,
creationflags=creationflags,
stdout=log,
stderr=subprocess.STDOUT,
close_fds=True,
env=env,
)
time.sleep(2)
if proc.poll() is not None:
raise RuntimeError(f"bot process exited during startup: returncode={proc.returncode}")
PID_FILE.write_text(str(proc.pid), encoding="utf-8")
return proc.pid
async def _notify_start() -> None:
sys.path.insert(0, str(PROJECT))
from app.main import load_env
load_env()
from app.monitor.notifier import send
mode = os.getenv("KIS_MOCK", "true")
dry = os.getenv("DRY_RUN", "true")
label = "[모의투자]" if mode == "true" else "[실거래]"
await send(f"{label} 자동매매 봇 시작 (DRY_RUN={dry})")
def main() -> int:
os.chdir(PROJECT)
_kill_existing_bots()
pid = _start_bot()
print(f"Bot started PID={pid}")
asyncio.run(_notify_start())
print("Discord start notification sent")
return 0
if __name__ == "__main__":
raise SystemExit(main())