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으로 상태 확인
- 직접 재시작할 일이 크게 줄었음