poolcoach / scripts /engine_worker.py
masterdanh's picture
deploy: snapshot for HF Space
78738de
Raw
History Blame Contribute Delete
3.35 kB
"""Worker engine recommend — mode queue (bàn giao 14, 04/08/2026).
Process TÁCH KHỎI API: nạp env + JIT Numba MỘT lần lúc boot, xong hết mới bật
heartbeat + nhận job (bối cảnh #3: JIT nguội ~40s/process, health không được
báo alive lúc còn đang JIT). Vòng đời sau đó:
BRPOP pc:jobs:recommend → app.engine.handle_job (MỘT code path với
in-process — bẫy 27/07) → LPUSH pc:result:{job_id} (TTL dọn rác)
Heartbeat: SET pc:worker:heartbeat TTL 15s mỗi vòng chờ — BRPOP timeout 5s
nên nhịp ~5s lúc rảnh, mỗi job lúc bận (search gate < 5s/cú → không hụt TTL).
Ctrl+C thoát sạch: xoá heartbeat để /api/health thấy worker chết NGAY thay vì
đợi TTL; job đang dở vẫn trả reply xong mới thoát (BRPOP là điểm ngắt).
Chạy tay (Redis: docker compose -f docker-compose.dev.yml up -d redis):
set REDIS_URL=redis://localhost:6379/0
python scripts\\engine_worker.py
Launcher: D:\\Khoa luan\\run_engine_worker.bat (ngoài repo, như mọi launcher).
"""
from __future__ import annotations
import os
import sys
import time
from pathlib import Path
# Repo KHÔNG cài package: src/ cho poolcoach_rl, ROOT cho app.* (quy ước
# scripts/ — xem CLAUDE.md; thiếu dòng này là lỗi đã tái phạm 24/07).
ROOT = Path(__file__).resolve().parents[1]
for _p in (ROOT / "src", ROOT):
if str(_p) not in sys.path:
sys.path.insert(0, str(_p))
from app import engine, jobqueue # noqa: E402
def main() -> int:
if not os.environ.get("REDIS_URL"):
print("engine_worker: thieu env REDIS_URL -- worker chi co nghia o "
"mode queue (vi du: redis://localhost:6379/0)", flush=True)
return 2
jobqueue.setup()
t0 = time.time()
from poolcoach_rl.envs import PositionPlayEnv
from poolcoach_rl.recommend import warmup
env_h = PositionPlayEnv()
print(f"[worker] env san sang sau {time.time() - t0:.1f}s -- warmup JIT "
f"Numba (~40s lan dau)...", flush=True)
warmup_s = warmup(env_h)
print(f"[worker] JIT xong sau {warmup_s:.1f}s -- bat heartbeat, cho job "
f"tren '{jobqueue.JOBS_KEY}'", flush=True)
import redis
served = 0
try:
while True:
try:
jobqueue.beat()
t_job = time.perf_counter()
if jobqueue.serve_one(lambda p: engine.handle_job(p, env_h),
timeout_s=5):
served += 1
print(f"[worker] job #{served} xong sau "
f"{time.perf_counter() - t_job:.2f}s", flush=True)
except redis.RedisError as e:
# Redis chết/khởi động lại KHÔNG được giết worker đã JIT ấm
# — chờ rồi thử lại; API phía kia tự trả 503 trong lúc này.
print(f"[worker] mat ket noi Redis ({type(e).__name__}: {e}) "
f"-- thu lai sau 2s", flush=True)
time.sleep(2)
except KeyboardInterrupt:
print(f"\n[worker] Ctrl+C -- thoat sach sau {served} job", flush=True)
finally:
jobqueue.clear_heartbeat() # health thay worker chet NGAY, khong doi TTL
jobqueue.teardown()
return 0
if __name__ == "__main__":
sys.exit(main())