diff --git a/lps/docs/operations.md b/lps/docs/operations.md index ee22f12..ba65325 100644 --- a/lps/docs/operations.md +++ b/lps/docs/operations.md @@ -101,15 +101,32 @@ SELECT avg(ip_request_no), count(*) FROM bot_detection; SELECT key, until, reason FROM search_negative ORDER BY created_at DESC; ``` +## 4-1. 관측·알림 (모니터링) + +| 엔드포인트/신호 | 용도 | +|------|------| +| `GET /healthz` | liveness — 프로세스 살아있는지(DB 무관) | +| `GET /readyz` | readiness — DB 도달성까지 확인(실패 503). LB/오케스트레이터용 | +| `GET /v1/lps/ops` | 운영 스냅샷: 큐 카운트 + `oldest_pending_sec`(큐 지연) + `dead_1h` + `stuck_running` + `blocks_1h`(최근 차단). 외부 모니터가 스크랩·알림 | +| 워커 하트비트 | `/tmp/lps_worker_heartbeat`(mtime) — 컨테이너 HEALTHCHECK 가 신선도<120s 로 행/좀비 워커 감지 | + +**임계 알림**(워커 ops-monitor): 초과 시 WARN 로그 + (env 있으면) Slack 호환 웹훅. +``` +LPS_ALERT_WEBHOOK=https://hooks.slack.com/... # 있으면 알림 전송 +LPS_ALERT_DEAD_1H=20 LPS_ALERT_BLOCKS_1H=80 LPS_ALERT_QUEUE_LAG_SEC=300 +``` + ## 5. 테스트 ```bash -python -m pytest +python -m pytest # 단위·통합(96) — 브라우저/네트워크 불필요 +LPS_LIVE=1 python -m pytest tests/test_browser_base.py::test_live_smoke # 라이브 스모크(셀렉터·안티봇 드리프트 감지) ``` > ⚠️ **워커가 실행 중이면 테스트가 깨집니다** — 워커가 같은 `lps_db`의 테스트 작업을 가로채기 때문. 테스트 전 워커를 멈추세요: > ```bash > pkill -f worker_main.py > ``` +> 라이브 스모크는 IP 의존·느려서 기본 skip. 배포 후 셀렉터가 깨졌는지 수동/야간 점검용. ## 6. 문제 해결 @@ -125,10 +142,20 @@ python -m pytest | 검색이 너무 느림/비쌈 | `result.metrics`로 소스별 시간·DECODO 바이트 확인. 대역폭이 대부분(오픈마켓 크롤) | | `result.desc = LPS_JOB_NOT_FOUND` | 존재하지 않거나 잘못된 job_id | -## 7. 배포 시 유의 (예정) -- Chrome을 **headless**로(서버엔 화면 없음) — 단 Cloudflare Turnstile은 headful이 더 잘 통과, 튜닝 필요 -- Docker 이미지에 **chromium 설치** 필요 -- **프록시(residential)** 사실상 필수 — 클라우드 IP는 쉽게 차단됨. 포트(IP) 풀은 넉넉히(회전 여유) -- 워커 여러 개는 **워커별 Chrome 프로필 분리 + 다른 프록시 IP**(이미 `WORKER_CONCURRENCY`로 자동 처리) -- 시크릿(config.local.toml)은 이미지에 굽지 말고 **마운트** 권장 -- **비용**: 대역폭이 원가의 대부분(오픈마켓 크롤) — 같은 상품 재크롤을 줄이는 TTL 캐시가 다음 절감 후보 +## 7. Docker 배포 + +```bash +# 루트에서 (DB 는 외부 PostgreSQL, host.docker.internal 로 연결) +docker compose build lps-api lps-worker +docker compose up -d lps-api lps-worker +docker logs -f lps-worker # 웜업·검색 로그 +docker ps # lps-worker "(healthy)" 확인 +``` +- **워커 = 헤드풀 Chromium + Xvfb**(`Dockerfile.worker`): **headless 는 Akamai·Cloudflare Turnstile 에 탐지됨**(실측). Xvfb 가상 디스플레이로 headful 실행. +- **API = lean**(`Dockerfile`, 브라우저 불필요). +- **시크릿은 이미지에 안 굽고 env 주입**: `OPENAI_API_KEY`·`DECODO_*`·`NAVER_KEYS` (compose 주석 참고). 로컬은 config.local.toml. +- **Chrome 프로필 영속 볼륨**(`lps-profiles:/profiles`, `LPS_PROFILE_DIR`): 재시작해도 cf_clearance 유지 → 재웜업 회피. +- **워커 헬스**: HEALTHCHECK(하트비트<120s)로 행 워커 감지. k8s 는 liveness probe 로 자동 재시작 연결. + +**남은 배포 과제**: API 인증·레이트리밋(비용 남용 방지), 다중 레플리카 시 분산 레이트리밋/프록시 IP 조정. +**비용**: 대역폭이 원가의 대부분(오픈마켓 크롤) — 같은 상품 재크롤을 줄이는 **TTL 캐시**가 다음 절감 후보.