CI/CD 안정성 강화: 동시 배포 방지, 자기 재빌드 제거, 헬스체크 추가
- deploy.sh: flock으로 동시 배포 방지, deployer를 빌드 대상에서 제외 - deploy.sh: 배포 후 헬스체크 (4개 서비스 /health 확인) - deploy.sh: 릴리즈 백업 최근 5개만 유지, 원자적 백업 (mv) - deploy-nas.sh: .env 동기화 제거 (운영 시크릿 보호), __pycache__ 제외 - deployer: threading.Lock으로 동시 배포 방어, TimeoutExpired 개별 처리 - docker-compose: deployer 포트 localhost 바인딩, stock-lab 환경변수 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,14 +1,18 @@
|
||||
import os, hmac, hashlib, subprocess
|
||||
import os, hmac, hashlib, subprocess, threading
|
||||
from fastapi import FastAPI, Request, HTTPException, BackgroundTasks
|
||||
import logging
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(name)s] %(levelname)s %(message)s")
|
||||
logger = logging.getLogger("deployer")
|
||||
|
||||
app = FastAPI()
|
||||
SECRET = os.getenv("WEBHOOK_SECRET", "")
|
||||
|
||||
if not SECRET:
|
||||
logger.warning("WEBHOOK_SECRET is not set! All webhooks will be rejected.")
|
||||
|
||||
_deploy_lock = threading.Lock()
|
||||
|
||||
def verify(sig: str, body: bytes) -> bool:
|
||||
if not SECRET or not sig:
|
||||
return False
|
||||
@@ -18,19 +22,26 @@ def verify(sig: str, body: bytes) -> bool:
|
||||
return any(hmac.compare_digest(sig, c) for c in candidates)
|
||||
|
||||
def run_deploy_script():
|
||||
"""배포 스크립트를 백그라운드에서 실행하고 로그를 남김"""
|
||||
logger.info("Starting deployment script...")
|
||||
"""배포 스크립트를 백그라운드에서 실행 (동시 실행 방지)"""
|
||||
if not _deploy_lock.acquire(blocking=False):
|
||||
logger.info("Deploy already in progress, skipping")
|
||||
return
|
||||
|
||||
try:
|
||||
# 타임아웃 10분 설정
|
||||
logger.info("Starting deployment script...")
|
||||
p = subprocess.run(["/bin/bash", "/scripts/deploy.sh"], capture_output=True, text=True, timeout=600)
|
||||
|
||||
|
||||
if p.returncode == 0:
|
||||
logger.info(f"Deployment SUCCESS:\n{p.stdout}")
|
||||
else:
|
||||
logger.error(f"Deployment FAILED ({p.returncode}):\n{p.stdout}\n{p.stderr}")
|
||||
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
logger.error("Deployment TIMEOUT (10 min exceeded)")
|
||||
except Exception as e:
|
||||
logger.exception(f"Exception during deployment: {e}")
|
||||
finally:
|
||||
_deploy_lock.release()
|
||||
|
||||
@app.get("/health")
|
||||
def health():
|
||||
|
||||
Reference in New Issue
Block a user