6095b4c7fa
- app/main.py: trading_loop while 루프 전체를 try/except로 감싸 예외 발생 시 로그+Discord 알림 후 루프 재개 (연속 10회 오류 시에만 종료) - scripts/_watchdog.py: 봇 PID 생존 확인, 죽어있으면 Discord 알림 + 자동 재시작 - scripts/run_watchdog.ps1: 워치독 PowerShell 래퍼 - scripts/setup_scheduler.ps1: StockBot_Watchdog 태스크 등록 추가 (5분 간격) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
82 lines
2.2 KiB
Python
82 lines
2.2 KiB
Python
"""
|
|
watchdog.py — 봇 생존 감시 + 자동 재시작
|
|
5분마다 실행 (작업 스케줄러) / 장중(09:00~15:10)에만 작동
|
|
"""
|
|
import asyncio, os, subprocess, sys
|
|
from datetime import datetime
|
|
|
|
PROJECT = r'C:\Users\whdwo\OneDrive\바탕 화면\stockbot_v3'
|
|
PID_FILE = os.path.join(PROJECT, 'logs', 'bot.pid')
|
|
|
|
os.chdir(PROJECT)
|
|
sys.path.insert(0, '.')
|
|
from app.main import load_env
|
|
load_env()
|
|
|
|
|
|
def is_process_alive(pid: int) -> bool:
|
|
r = subprocess.run(
|
|
['tasklist', '/FI', f'PID eq {pid}', '/NH'],
|
|
capture_output=True, text=True,
|
|
)
|
|
return str(pid) in r.stdout
|
|
|
|
|
|
def get_pid() -> int | None:
|
|
try:
|
|
return int(open(PID_FILE).read().strip())
|
|
except Exception:
|
|
return None
|
|
|
|
|
|
def restart_bot() -> int:
|
|
proc = subprocess.Popen(
|
|
[sys.executable, 'app/main.py'],
|
|
creationflags=subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP,
|
|
stdout=open('logs/bot_stderr.log', 'a', encoding='utf-8'),
|
|
stderr=subprocess.STDOUT,
|
|
close_fds=True,
|
|
)
|
|
with open(PID_FILE, 'w') as f:
|
|
f.write(str(proc.pid))
|
|
return proc.pid
|
|
|
|
|
|
async def main():
|
|
now = datetime.now()
|
|
now_str = now.strftime("%H:%M")
|
|
|
|
# 장 외 시간은 체크 안 함
|
|
if not ("09:00" <= now_str <= "15:10"):
|
|
print(f"[{now_str}] 장 외 시간 — 워치독 종료")
|
|
return
|
|
|
|
from app.monitor.notifier import send
|
|
|
|
pid = get_pid()
|
|
|
|
if pid is None:
|
|
msg = f"[경고] 봇 PID 파일 없음 — 봇이 실행되지 않은 상태입니다 ({now_str})"
|
|
print(msg)
|
|
await send(msg)
|
|
new_pid = restart_bot()
|
|
await send(f"[복구] 봇 자동 재시작 완료 PID={new_pid}")
|
|
return
|
|
|
|
if is_process_alive(pid):
|
|
print(f"[{now_str}] 봇 정상 실행 중 PID={pid}")
|
|
return
|
|
|
|
# 봇이 죽어있음
|
|
msg = f"[긴급] 봇 프로세스 종료 감지 (PID={pid}) — 자동 재시작 시도"
|
|
print(msg)
|
|
await send(msg)
|
|
|
|
new_pid = restart_bot()
|
|
await send(f"[복구] 봇 자동 재시작 완료 PID={new_pid} ({now_str})")
|
|
print(f"봇 재시작 완료 PID={new_pid}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|