本学期参与「代码卫士 AI」MVP 建设,我主要负责后端基础架构:在 FastAPI 上搭建可演进的 REST 服务,用 Celery + Redis 承接审查类长任务,用关系型数据库沉淀项目、PR、审查结果与治理数据;同时对接 GitHub 生态——从 GitHub App / Webhook 的注册配置,到 PR 数据拉取与评论回写,形成可观测、可扩展的一条流水线。

结合课题要求,我的工作可归纳为五块(也是后续系列文章的目录骨架):

方向 目标 与仓库的对应关系(摘要)
GitHub 集成 App 注册、Webhook 配置;支持 PR 的 openedsynchronize 等事件 路由 POST /api/v1/webhooks/github,负载模型含 actionpull_requestrepository
API 与异步 FastAPI REST;Celery + Redis;至少 3 路审查任务并发 celery_app + review.process;生产环境通过 celery worker --concurrency=3(或与容器副本数配合)落地
数据层 不少于 8 张核心表;列表/详情查询体验 当前模型共 11 张表(见下文),关键外键与索引已用于列表场景
业务接口 项目增删改查;多项目接入 数据上已有 projectsrepository_bindings;Webhook 可按仓库 自动建项目/绑定;显式项目 CRUD 接口可作为下一阶段接口层补全
PR 与评论 PR 数据获取、评论发布;发布成功率 ≥95% GitProvider 抽象:GitHubProvider 调 GitHub REST;publish_draft_comment 走 publish_comment

下文按技术栈展开。

从一条请求说起。GitHub 往我们这边推 Webhook 时,路由挂在 POST /api/v1/webhooks/github,返回的是 202,意思是「我收到了,后面异步做」,避免 GitHub 一直等超时然后疯狂重试。对应代码很直观,github_webhook 这个函数把 body 解析成 GitHubWebhookPayload,然后交给 create_review_task_from_github_webhook 去建任务并入队:

webhooks.pyLines 15-26

@router.post(

"/webhooks/github",

response_model=ReviewTaskSummaryRead,

status_code=status.HTTP_202_ACCEPTED,

)

def github_webhook(

payload: GitHubWebhookPayload,

db: Session = Depends(get_db_session),

actor: str = Depends(get_actor),

) -> ReviewTaskSummaryRead:

task = create_review_task_from_github_webhook(db, payload, actor)

return serialize_review_task_summary(task)

        负载模型里带了 action 和 pull_request,这和官方 PR 事件的 JSON 结构是对齐的。课题里要求重点支持 opened 和 synchronize,我现在的理解是:在 GitHub App 或 Webhook 配置里先只订阅需要的事件,服务端再视情况用 action 做白名单过滤,免得每次 push 都触发一整条审查流水线。这部分过滤逻辑如果还没写进仓库,就是我后面要补的一小步,而不是架构上推翻重来。

        任务建好之后,真正干活的是 Celery。enqueue_review_task 里一行 process_review_task.delay(review_task_id),就把审查丢进队列;Worker 里跑的是 ReviewPipelineService,去拉 PR、跑分析、生成草稿评论。开发时可以把 CELERY_TASK_ALWAYS_EAGER 设成 true,任务在当前进程同步执行,调试不用起 Redis;上线再关掉,用 Redis 做 broker,这和 docker-compose 里配的环境变量是一套思路。

review_tasks.pyLines 18-19

def enqueue_review_task(review_task_id: int) -> None:

process_review_task.delay(review_task_id)

         并发方面,课题要求至少三个审查任务并行,这在我这边的落点主要是 Celery Worker 的并发参数或实例个数,而不是在业务代码里手写三个线程。部署时把 celery worker 的 --concurrency 调到不小于三,再配合队列监控,才算把「能并行」变成「可观测、可调」。

         数据库是我花时间的另一块。现在模型里一共有十一张表,从 projectsrepository_bindings 到 pull_request_snapshotsreview_taskschanged_filesfindingsreview_summaries,再加上 draft_comments、规则与规范映射、审计日志,已经超过至少八张核心表的底线。有意思的是项目是怎么进来的:create_review_task_from_github_webhook 里如果根据仓库 full_name 找不到 Project,会直接创建一个,并挂上 RepositoryBinding。也就是说多项目接入在数据路径上是通的,第一次 Webhook 就相当于「自动登记」;若要做完整的管理端增删改查,多半是在现有表结构上补 REST 接口和权限,而不是从零设计一套新模型。

      和 GitHub 的读写我习惯看成同一件事的两面,代码里用 GitProvider 抽象兜住了。GitHubProvider 里 fetch_p  ull_request 走 REST 拉 PR 和 diff,publish_comment 往 issues 评论接口 POST 正文;本地或没有令牌时用 Mock,不至于整条链路断掉。发布草稿评论的业务在 publish_draft_comment 里调 provider.publish_comment,成功就改状态、写 published_url,并记一条审计。以后若要谈「评论发布成功率不低于百分之九十五」,我会从这里的成功返回和异常分支去埋指标,再加上对 429 和 5xx 的重试策略,而不是只停留在口号上。

git.pyLines 44-58

class GitProvider(ABC):

@abstractmethod

def fetch_pull_request(

self, binding: RepositoryBinding, snapshot: PullRequestSnapshot

) -> PullRequestData:

raise NotImplementedError

@abstractmethod

def publish_comment(

self,

binding: RepositoryBinding,

snapshot: PullRequestSnapshot,

draft_comment: DraftComment,

) -> PublishResult:

raise NotImplementedError

本篇需要交代清楚的有三层:HTTP 层快速接住 Webhook 并落库,异步层用 Celery 把重活搬走,持久层用十几张表把项目和审查生命周期串起来;Git 侧则统一走 GitProvider,方便以后换实现或加重试。诚实讲,Webhook 签名校验、幂等去重、项目 CRUD 接口,这些在仓库里有的还没写全,正是我接下来几周要对着课题指标一点点补上的。接下来我打算从「GitHub App 注册到 Secret 进环境变量,再到第一笔带签名的请求打进来」这条线开始着手进行,下一步获得可交付的内容

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐