fix: deployer webhook timeout - implement async background task
This commit is contained in:
@@ -1,5 +1,10 @@
|
|||||||
import os, hmac, hashlib, subprocess
|
import os, hmac, hashlib, subprocess
|
||||||
from fastapi import FastAPI, Request, HTTPException
|
from fastapi import FastAPI, Request, HTTPException, BackgroundTasks
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# 로깅 설정
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
logger = logging.getLogger("deployer")
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
SECRET = os.getenv("WEBHOOK_SECRET", "")
|
SECRET = os.getenv("WEBHOOK_SECRET", "")
|
||||||
@@ -9,16 +14,28 @@ def verify(sig: str, body: bytes) -> bool:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
mac = hmac.new(SECRET.encode(), msg=body, digestmod=hashlib.sha256).hexdigest()
|
mac = hmac.new(SECRET.encode(), msg=body, digestmod=hashlib.sha256).hexdigest()
|
||||||
|
|
||||||
# Gitea가 보내는 포맷이 케이스별로 달라서 둘 다 허용
|
|
||||||
candidates = {mac, f"sha256={mac}"}
|
candidates = {mac, f"sha256={mac}"}
|
||||||
return any(hmac.compare_digest(sig, c) for c in candidates)
|
return any(hmac.compare_digest(sig, c) for c in candidates)
|
||||||
|
|
||||||
|
def run_deploy_script():
|
||||||
|
"""배포 스크립트를 백그라운드에서 실행하고 로그를 남김"""
|
||||||
|
logger.info("Starting deployment script...")
|
||||||
|
try:
|
||||||
|
# 타임아웃 10분 설정
|
||||||
|
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 Exception as e:
|
||||||
|
logger.exception(f"Exception during deployment: {e}")
|
||||||
|
|
||||||
@app.post("/webhook")
|
@app.post("/webhook")
|
||||||
async def webhook(req: Request):
|
async def webhook(req: Request, background_tasks: BackgroundTasks):
|
||||||
body = await req.body()
|
body = await req.body()
|
||||||
|
|
||||||
# ✅ 여기(함수 안)에서 헤더 읽기
|
|
||||||
sig = (
|
sig = (
|
||||||
req.headers.get("X-Gitea-Signature")
|
req.headers.get("X-Gitea-Signature")
|
||||||
or req.headers.get("X-Hub-Signature-256")
|
or req.headers.get("X-Hub-Signature-256")
|
||||||
@@ -28,10 +45,8 @@ async def webhook(req: Request):
|
|||||||
if not verify(sig, body):
|
if not verify(sig, body):
|
||||||
raise HTTPException(401, "bad signature")
|
raise HTTPException(401, "bad signature")
|
||||||
|
|
||||||
# 배포 스크립트 실행
|
# ✅ 비동기 실행: Gitea에게는 즉시 OK 응답을 주고, 배포는 뒤에서 실행
|
||||||
p = subprocess.run(["/bin/bash", "/scripts/deploy.sh"], capture_output=True, text=True)
|
background_tasks.add_task(run_deploy_script)
|
||||||
if p.returncode != 0:
|
|
||||||
raise HTTPException(500, f"deploy failed:\n{p.stdout}\n{p.stderr}")
|
|
||||||
|
|
||||||
return {"ok": True, "out": p.stdout}
|
return {"ok": True, "message": "Deployment started in background"}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user