pytorch/crcr-test

GitHub: pytorch/crcr-test

PyTorch 树外后端跨仓库 CI 中继系统的参考实现,用于演示下游仓库如何接收上游 PyTorch 事件并自动触发自身 CI。

Stars: 3 | Forks: 2

# 跨仓库 CI 中继 (CRCR) — 接入指南 本仓库用作 [跨仓库 CI 中继 (CRCR)](https://github.com/pytorch/rfcs/blob/master/RFC-0050-Cross-Repository-CI-Relay-for-PyTorch-Out-of-Tree-Backends.md) 系统的**参考实现与测试平台**。它演示了树外 (OOT) 后端如何接收上游 PyTorch 事件,并作为响应运行其自身的 CI。 使用本指南将您的下游仓库接入 CRCR pipeline。 ## 工作原理 当 `pytorch/pytorch` 上开启 PR 或推送代码时,[pytorch-fdn-cross-repo-ci-relay](https://github.com/apps/pytorch-fdn-cross-repo-ci-relay) GitHub App 会向所有已批准的下游仓库发送 `repository_dispatch` 事件。您的仓库接收这些事件后,即可触发构建、测试或任何工作流作为响应。 ``` pytorch/pytorch (PR / push) │ ▼ CRCR Relay Bot (pytorch-fdn-cross-repo-ci-relay) │ ▼ repository_dispatch │ ├──► your-org/your-repo (your workflow runs) ├──► Ascend/pytorch ├──► riseproject-dev/pytorch-ci └──► pytorch/crcr-test ``` ## 信任级别 每个下游仓库都会被分配一个信任级别,该级别决定了它与 PyTorch CI 的集成深度: | 级别 | 名称 | 描述 | |-------|------|-------------| | **L1** | 接入 (Onboarding) | 事件将转发至下游,但上游不会收到反馈。 | | **L2** | 观察 (Observation) | 下游 CI 结果将显示在 [HUD](https://hud.pytorch.org) 页面上,但不会显示在 PR 上。 | | **L3** | 稳定 (Stable) | 当应用 `ciflow/oot/` 标签时,会在 PR 上添加非阻塞性的检查运行 (check run)。 | | **L4** | 成熟 (Mature) | 会在每个 PR 上添加阻塞性的检查运行;专为关键加速器保留。 | 所有新仓库均从 **L1** 开始。晋升到更高级别取决于其展现出的稳定性与可靠性。 ## 接入步骤 ### 步骤 1:安装 CRCR GitHub App 在您的下游仓库中安装 [pytorch-fdn-cross-repo-ci-relay](https://github.com/apps/pytorch-fdn-cross-repo-ci-relay) GitHub App。 如需批准安装,请联系 **[@albanD](https://github.com/albanD)** 或 **[@atalman](https://github.com/atalman)**。 ### 步骤 2:将您的仓库添加至白名单 向 [`pytorch/pytorch`](https://github.com/pytorch/pytorch) 提交一个 PR,将您的仓库添加到白名单文件中: **文件:** [`.github/allowlist.yml`](https://github.com/pytorch/pytorch/blob/main/.github/allowlist.yml) 将您的仓库添加到相应的级别下(新仓库从 L1 开始): ``` L1: - pytorch/crcr-test - Ascend/pytorch - riseproject-dev/pytorch-ci - your-org/your-repo # ← add your repo here ``` ### 步骤 3:创建 Dispatch 接收器工作流 在您的仓库中创建一个 GitHub Actions 工作流,用于监听 `repository_dispatch` 事件。中继器会发送两种事件类型: - **`push`** — 当代码推送到 `main` 或创建了 ciflow 标签时触发(例如,`refs/tags/ciflow/trunk/`) - **`pull_request`** — 当 PR 被开启、重新开启、同步或关闭时触发 在您的仓库中创建 `.github/workflows/out-of-tree-ci.yml`: ``` name: PyTorch Out-of-Tree Dispatch on: repository_dispatch: types: - pull_request - push run-name: >- Dispatch - ${{ github.event.client_payload.event_type == 'pull_request' && format( 'PR #{0} ({1})', github.event.client_payload.payload.pull_request.number, github.event.client_payload.payload.action ) || github.event.client_payload.payload.ref }} concurrency: group: >- oot-${{ github.event.client_payload.payload.repository.full_name }}-${{ github.event.client_payload.payload.pull_request.number || github.run_id }} cancel-in-progress: true permissions: actions: write id-token: write # required for L2+ callback authentication (OIDC) jobs: cancel-workflow: if: ${{ github.event.client_payload.payload.action == 'closed' }} runs-on: ubuntu-latest steps: - run: echo "PR closed, canceling older runs in the same concurrency group" build-and-test: if: ${{ github.event.client_payload.payload.action != 'closed' }} # listen to the specific action types you need (opened, reopened, synchronize) runs-on: ubuntu-latest steps: - name: Checkout your repository uses: actions/checkout@v4 - name: Checkout PyTorch at dispatched SHA uses: actions/checkout@v4 with: repository: pytorch/pytorch ref: ${{ github.event.client_payload.payload.pull_request.head.sha || github.event.client_payload.payload.after }} path: pytorch # Add your build and test steps here - name: Build and test run: | echo "Building against PyTorch SHA: ${{ github.event.client_payload.payload.pull_request.head.sha || github.event.client_payload.payload.after }}" # your build commands here - name: Log event to step summary if: always() run: | cat <<'SUMMARY' >> $GITHUB_STEP_SUMMARY ```json ${{ toJson(github.event) }} ``` SUMMARY ``` ### 步骤 4:验证集成 步骤 1–3 完成后,您的工作流将开始接收 dispatch。您可以通过以下方式进行验证: 1. 检查您仓库的 **Actions** 选项卡中的 `repository_dispatch` 事件 2. 查找由 `pytorch-fdn-cross-repo-ci-relay[bot]` 触发的运行记录 3. 检查步骤摘要以获取完整的事件 payload ## Dispatch Payload 结构 中继器会将原始的 GitHub 事件封装在 `client_payload` 内部: ``` { "event_type": "push", "client_payload": { "event_type": "push", "payload": { "ref": "refs/tags/ciflow/trunk/184534", "after": "abc123...", "deleted": false, "base_ref": "refs/heads/main", "repository": { "full_name": "pytorch/pytorch" } } } } ``` 对于 `pull_request` 事件: ``` { "event_type": "pull_request", "client_payload": { "event_type": "pull_request", "payload": { "action": "opened", "pull_request": { "number": 184442, "title": "My PR title", "head": { "sha": "abc123...", "repo": { "full_name": "user/pytorch" } } }, "repository": { "full_name": "pytorch/pytorch" } } } } ``` ## 关键字段参考 | 字段 | 路径 | 描述 | |-------|------|-------------| | 事件类型 | `github.event.client_payload.event_type` | `push` 或 `pull_request` | | 上游仓库 | `github.event.client_payload.payload.repository.full_name` | 始终为 `pytorch/pytorch` | | Push ref | `github.event.client_payload.payload.ref` | Git ref(例如,`refs/tags/ciflow/trunk/12345`) | | Push SHA | `github.event.client_payload.payload.after` | push 事件的 commit SHA | | PR 编号 | `github.event.client_payload.payload.pull_request.number` | pull_request 事件的 PR 编号 | | PR 操作 | `github.event.client_payload.payload.action` | `opened`、`reopened`、`synchronize`、`closed` | | PR head SHA | `github.event.client_payload.payload.pull_request.head.sha` | PR 的 head commit SHA | | PR head 仓库 | `github.event.client_payload.payload.pull_request.head.repo.full_name` | Fork 仓库(如适用) | ## 速率限制 CRCR 中继 Lambda 实施了服务端速率限制,以保护后端基础设施(Redis、ClickHouse)免受回调突发的影响。目前的限制为所有下游仓库**每分钟 60 个请求**。当多个下游仓库并发发送回调时——例如,在一次大型上游 PR 推送扇出到多个仓库期间——中继器可能会响应 **HTTP 429 (Too Many Requests)**。 ### 429 发生时的情况 默认的回调操作 (`cross-repo-ci-relay-callback`) 使用 `curl --fail-with-body`,它将任何非 2xx 响应视为硬性失败。单次瞬时的 429 就会导致回调步骤失败并使任务标记为出错,即使速率限制是暂时的。 ### 推荐:带退避机制的客户端重试 正如 [#8](https://github.com/pytorch/crcr-test/issues/8) 中所讨论的,首选的缓解措施是**带有指数退避 (exponential backoff) 的客户端重试**,而不是提高服务端的阈值。服务端限制器是一种保护机制,应当予以保留——任何固定限制都无法保证并发的突发流量永远不会超过它。 **为什么选择重试而不是提高限制**(根据 [@can-gaa-hou](https://github.com/can-gaa-hou)): ### 下游仓库的最佳实践 1. **为工作流步骤添加抖动 (jitter)** — 如果您的工作流中有多个发送回调的任务,请使用随机延迟(`sleep $((RANDOM % 10))`)错开执行,以避免同步突发。 2. **预见 429 响应** — 将您的回调步骤设计为能够容忍瞬时故障。在 `curl` 调用周围使用重试包装器可以防止不必要的任务失败。 3. **遵守 `Retry-After` 标头** — 如果中继器在 429 响应中包含 `Retry-After` 标头,请至少等待相应时间后再重试。 4. **限制并发回调任务** — 使用 GitHub Actions 并发组 (concurrency groups),避免因同一仓库的并行回调导致中继器过载。 ### 计划中的改进 - 在 `cross-repo-ci-relay-callback` 操作中实现带有退避机制的客户端重试 ([pytorch/test-infra](https://github.com/pytorch/test-infra)) - 在中继 Lambda 中支持 `Retry-After` 标头 ## 相关资源 - [RFC-0050: 跨仓库 CI 中继](https://github.com/pytorch/rfcs/blob/master/RFC-0050-Cross-Repository-CI-Relay-for-PyTorch-Out-of-Tree-Backends.md) — 完整的 CRCR 设计规范 - [白名单](https://github.com/pytorch/pytorch/blob/main/.github/allowlist.yml) — 当前已批准的下游仓库列表 - [CRCR 中继 GitHub App](https://github.com/apps/pytorch-fdn-cross-repo-ci-relay) — 中继机器人 - [追踪 Issue](https://github.com/pytorch/pytorch/issues/175022) — CRCR 追踪 Issue ## 联系人 如有关于接入、安装批准或晋升至更高信任级别的问题: - **[@albanD](https://github.com/albanD)** — PyTorch 核心维护者 - **[@atalman](https://github.com/atalman)** — PyTorch 开发基础设施 (Dev Infra) - **[@groenenboomj](https://github.com/groenenboomj)** - **[@jewelkm89](https://github.com/jewelkm89)** - **[@subinz1](https://github.com/subinz1)** - **[@fffrog](https://github.com/fffrog)**
标签:PyTorch, 威胁情报, 开发者工具, 开源框架, 持续集成, 搜索引擎查询, 跨仓库协同