Python 봇 여러 개를 한 번에 시작하고 자동 재시작까지 — start_all.py 구조

봇이 죽으면 자동으로 다시 살리고, 코드 파일이 바뀌면 자동으로 재시작하는 봇 관리 스크립트. 실제 운영 코드 기반.

Python 봇 여러 개를 한 번에 시작하고 자동 재시작까지 — start_all.py 구조

문제

봇이 10개 넘습니다. 매번 터미널에서 하나씩 실행하면:

python nim_bot.py
python deepseek_bot.py
python gemini_bot.py
# ... 계속

불편합니다. 그리고 하나 죽으면 모릅니다. 수동으로 다시 켜야 합니다.


해결: start_all.py

한 번 실행하면 모든 봇이 켜지고, 죽으면 자동으로 다시 살아납니다.


PID 파일로 중복 실행 방지

실수로 두 번 실행하면 봇이 두 배로 뜹니다. Telegram 메시지도 두 번씩 옵니다.

PID 파일로 방지:

PID_FILE = "data/start_all.pid"

def _check_pid_alive(pid: int) -> bool:
    try:
        os.kill(pid, 0)  # 신호 0 = 프로세스 존재 확인만
        return True
    except Exception:
        return False

# 실행 시 확인
if os.path.exists(PID_FILE):
    with open(PID_FILE) as f:
        old_pid = int(f.read().strip())
    if _check_pid_alive(old_pid):
        print(f"이미 실행 중 (PID {old_pid}). 먼저 종료하세요.")
        sys.exit(1)

# 현재 PID 저장
with open(PID_FILE, "w") as f:
    f.write(str(os.getpid()))

봇 목록 정의

BOT_SCRIPTS = [
    ("뉴스봇",     "nim_bot.py",      "NIM_BOT_TOKEN"),
    ("코딩봇",     "qwen36_bot.py",   "CODER_BOT_TOKEN"),
    ("Gemma봇",   "helper_bot.py",   "GEMMA_BOT_TOKEN"),
    ("Gemini봇",  "gemini_bot.py",   "GEMINI_BOT_TOKEN"),
    ("DeepSeek봇", "deepseek_bot.py", "DEEPSEEK_BOT_TOKEN"),
    ("코덱스봇",   "codex_bot.py",    "CODEX_BOT_TOKEN"),
    ("대시보드",   "jarvis_dashboard.py", None),  # 토큰 불필요
]

3번째 항목이 환경변수 이름입니다. 없으면 해당 봇은 건너뜁니다.


subprocess로 봇 시작

import subprocess
import os

processes: dict[str, subprocess.Popen] = {}

def start_bot(name: str, script: str, token_env: str | None) -> subprocess.Popen | None:
    # 토큰 확인
    if token_env and not os.getenv(token_env):
        print(f"{name}: 토큰 없음 ({token_env}), 건너뜀")
        return None
    
    proc = subprocess.Popen(
        [sys.executable, script],
        cwd=BOT_DIR,
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
    )
    print(f"{name} 시작 (PID {proc.pid})")
    return proc

# 모든 봇 시작
for name, script, token_env in BOT_SCRIPTS:
    proc = start_bot(name, script, token_env)
    if proc:
        processes[name] = proc

크래시 감지 & 자동 재시작

메인 루프에서 10초마다 각 봇 프로세스 상태를 확인합니다.

MAX_RESTART = 5  # 최대 재시작 횟수
restart_counts: dict[str, int] = {name: 0 for name, _, _ in BOT_SCRIPTS}

def monitor_loop():
    while True:
        time.sleep(10)
        
        for name, script, token_env in BOT_SCRIPTS:
            proc = processes.get(name)
            if proc is None:
                continue
            
            # 프로세스 종료 확인
            if proc.poll() is not None:
                exit_code = proc.returncode
                count = restart_counts[name]
                
                if count >= MAX_RESTART:
                    print(f"{name}: 재시작 {MAX_RESTART}회 초과. 포기.")
                    continue
                
                print(f"{name}: 종료됨 (코드 {exit_code}). 재시작 ({count+1}/{MAX_RESTART})")
                new_proc = start_bot(name, script, token_env)
                if new_proc:
                    processes[name] = new_proc
                    restart_counts[name] += 1

파일 감시 — 코드 바뀌면 자동 재시작

개발 중에 봇 코드를 수정하면 수동으로 재시작해야 합니다. 파일 감시로 자동화:

import os

_file_mtimes: dict[str, float] = {}
DEBOUNCE_SECS = 4.0  # 저장 후 4초 기다렸다가 재시작

def watch_files():
    while True:
        time.sleep(1)
        
        for name, script, token_env in BOT_SCRIPTS:
            path = os.path.join(BOT_DIR, script)
            if not os.path.exists(path):
                continue
            
            mtime = os.path.getmtime(path)
            last_mtime = _file_mtimes.get(name, 0)
            
            if mtime > last_mtime + 0.1:  # 파일이 변경됨
                _file_mtimes[name] = mtime
                
                # 디바운스: 연속 저장 시 마지막 저장 후 4초 뒤 재시작
                _pending_restarts[name] = time.time()
            
            # 디바운스 타임 지났으면 재시작
            if name in _pending_restarts:
                if time.time() - _pending_restarts[name] > DEBOUNCE_SECS:
                    del _pending_restarts[name]
                    print(f"{name}: 파일 변경 감지. 재시작.")
                    restart_bot(name, script, token_env)

코드 저장 → 4초 후 자동 재시작. 개발 중에 편합니다.


자가진단 (10분마다)

10분마다 각 봇 상태를 확인하고 Telegram으로 보고합니다.

HEALTH_INTERVAL = 600  # 10분

def health_check():
    while True:
        time.sleep(HEALTH_INTERVAL)
        
        alive = [name for name, proc in processes.items() if proc.poll() is None]
        dead = [name for name, proc in processes.items() if proc.poll() is not None]
        
        if dead:
            msg = f"⚠️ 봇 상태 이상\n살아있음: {', '.join(alive)}\n죽어있음: {', '.join(dead)}"
            send_telegram(msg)

실행

# 개발 시 직접 실행
python start_all.py

# 서버 운영 시 Task Scheduler로 등록
# PC 시작 시 자동 실행

효과

  • 봇이 죽어도 자동으로 살아남
  • 코드 수정하면 자동으로 반영
  • 아침에 Telegram으로 상태 확인
  • 직접 재시작할 일이 크게 줄었음
#Python#프로세스관리#자동재시작#파일감시#자동화