o2o-negosium-original/lps/web_main.py
민헌 da9bd7750c feat(lps): 작업 큐 엔진 — PostgreSQL 원자적 claim + lease + dead-letter
레퍼런스의 DB-큐 반면교사를 전부 뒤집는 큐 엔진을 구축한다.
 - 원자적 claim: FOR UPDATE SKIP LOCKED 서브쿼리 + 같은 UPDATE + RETURNING
   → 워커 다수여도 이중 할당 원천 불가(fetch/claim 미분리)
 - 모든 전이는 조건부 CAS(status/worker_id 가드) + RETURNING
 - 복구는 timeout 추측이 아닌 lease 만료 소유권 기반(reaper 회수)
 - 재시도 지수백오프 + max_attempts + dead-letter 를 큐에 내장(스크립트 난립 제거)
 - dedupe_key 부분 유니크로 활성 중복 차단, counts()로 관측(수동 psql 대체)

- enums: JobStatus(PENDING/RUNNING/DONE/DEAD)·JobType(SEARCH/OUTBOX)
- models: job 테이블(무FK·SMALLINT코드·TIMESTAMPTZ, claim/lease/dedupe 인덱스)
- crud/job_crud: JobQueue(enqueue/claim/complete/fail/renew_lease/reap/counts)
- tests: 동시 8워커 이중할당0·lease회수·재시도→dead·소유권가드 등 8건(실 lps_db)

부수: 포트 9400→9600 (negodata 9400 충돌 회피)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 16:37:32 +09:00

42 lines
1.3 KiB
Python

# 실행 방법
# pip install -r requirements.txt
# python web_main.py # 기본 local 환경
# APP_ENV=dev python web_main.py # 환경 지정
#
# 또는 uvicorn 직접 실행:
# uvicorn router.router:app --reload --host=0.0.0.0 --port=9600
import uvicorn
from common.logger import LOG
from config.server_configs import web_server_config
LOG.SetPrefix(web_server_config.server_name)
# import 시점에 app 및 DB 세션 매니저(싱글톤)가 초기화된다.
import router.router
if __name__ == "__main__":
LOG.i(f"Server Name : {web_server_config.server_name}")
LOG.i(f"Server Port : {web_server_config.port}")
LOG.i(f"API Server start time : {router.router.API_SERVER_START_TIME}")
if web_server_config.is_ssl:
uvicorn.run(
"router.router:app",
host="0.0.0.0",
port=web_server_config.port,
access_log=False,
workers=web_server_config.process_count,
ssl_keyfile="./SSL/key.pem",
ssl_certfile="./SSL/cert.pem",
)
else:
uvicorn.run(
"router.router:app",
host="0.0.0.0",
port=web_server_config.port,
access_log=False,
workers=web_server_config.process_count,
)