Production-grade: webhook execution, Postgres backup, rate limit, worker timeout/retry

GitHub webhook: delivery-id dedup persisted in webhook_deliveries,
/fix-review creates a queued task with audit (no model run in the
webhook itself), check_run/check_suite parsing without mutating
task state (CI backfill still via pr-checks).
Control plane: Postgres pg_dump backup branch + POST /admin/backup
(maintainer+, password only via PGPASSWORD env), per-key/IP rate
limit (default 120/min, 429), health returns backend + db_ok,
metrics by_status always has all seven status keys.
Worker: per-task timeout (default 1800s, --task-timeout), timeout
is failed not interrupted, limited retries (default 1, backoff,
fallback failures not re-retried), stale codex- container cleanup
on loop/CLI start.
Tests: cloud 271 (267 pass, 4 skipped are pre-existing real-
Postgres tests), host 27 pass.
This commit is contained in:
host committed 2026-10-26 03:55:07 +08:00
1 parent 86160ad175
commit 33841355b5
9 files changed
+1366 -52

No files matched your search

+100
View File
@@ -26,6 +26,8 @@ from cloud.db import connect as _db_connect
__all__ = [
"verify_github_signature",
"parse_github_pr_comment",
"parse_github_check_run",
"WebhookDeliveryStore",
"verify_slack_signature",
"parse_slack_command",
"SlackUserMap",
@@ -94,6 +96,104 @@ def parse_github_pr_comment(payload):
}
def parse_github_check_run(payload):
"""解析 GitHub check_run / check_suite 事件,返回结构化结果或 None。
只在结论已定的时候返回:check_run / check_suite 的 conclusion
为 "success" 或 "failure" 时返回::
{"type": "check_run", "repo": ..., "head_sha": ...,
"conclusion": ..., "check_name": ...}
其中 repo 取 repository full_name,head_sha 取 check_run /
check_suite 的 head_sha,check_name 取 check_run 的 name
(check_suite 没有单项名时为 None)。结论为 None / 进行中
(如 queued / in_progress / neutral / cancelled 等)时返回 None,
调用方不应据此建任务或改任务状态——CI 状态回填由 pr-checks
主动拉取,webhook 只做通知解析。
"""
if not isinstance(payload, dict):
return None
for key in ("check_run", "check_suite"):
run = payload.get(key)
if not isinstance(run, dict):
continue
conclusion = run.get("conclusion")
if conclusion not in ("success", "failure"):
return None
repository = payload.get("repository") or {}
return {
"type": "check_run",
"repo": repository.get("full_name"),
"head_sha": run.get("head_sha"),
"conclusion": conclusion,
"check_name": run.get("name"),
}
return None
class WebhookDeliveryStore:
"""GitHub webhook delivery 去重(持久化,不只放内存)。
表 webhook_deliveries:delivery_id(主键,X-GitHub-Delivery 头)、
event、repo、created_at(epoch 秒)。claim() 第一次返回 True,
同一 delivery_id 第二次返回 False,调用方应直接回 200 且标记
duplicate,不重复建任务、不重复记审计。INSERT 冲突时先按
IntegrityError 处理,再回查一次确认(PG 适配层抛的完整性错误
类型与 SQLite 不同,这里按“插入失败后回查存在即重复”处理,
不依赖具体异常类名)。
"""
def __init__(self, db_path):
self.db_path = db_path
self._conn = _db_connect(db_path)
self._conn.execute(
"CREATE TABLE IF NOT EXISTS webhook_deliveries("
"delivery_id TEXT PRIMARY KEY, "
"event TEXT, "
"repo TEXT, "
"created_at REAL)"
)
self._conn.commit()
def claim(self, delivery_id, event=None, repo=None):
"""认领一次 delivery:首次 True,重复 False。空 id 不认领。"""
if not delivery_id:
return True
row = self._conn.execute(
"SELECT delivery_id FROM webhook_deliveries WHERE delivery_id = ?",
(delivery_id,),
).fetchone()
if row is not None:
return False
try:
self._conn.execute(
"INSERT INTO webhook_deliveries"
"(delivery_id, event, repo, created_at)"
" VALUES(?, ?, ?, ?)",
(delivery_id, event, repo, time.time()),
)
self._conn.commit()
except Exception:
try:
self._conn.rollback()
except Exception:
pass
row = self._conn.execute(
"SELECT delivery_id FROM webhook_deliveries"
" WHERE delivery_id = ?",
(delivery_id,),
).fetchone()
if row is not None:
return False
raise
return True
def close(self):
"""关闭数据库连接(可选,单测/退出时用)。"""
self._conn.close()
def verify_slack_signature(signing_secret, timestamp, body, signature_header):
"""校验 Slack 请求签名(防重放)。