如何在Github Actions中为不同PR触发的工作流任务创建队列?
解决Github Actions多PR工作流并发排队的问题
Github Actions自带的concurrency配置会直接取消同组里的其他任务,根本没法实现我们要的“最多2-3个并行、其余排队等位置”的需求,这里给两个可行的实现方案:
方案一:用自定义脚本结合Github API做排队检查
在CI工作流的最前面加一个步骤,通过Github API查询当前正在跑的同类型工作流数量,没到上限就继续,到了就循环等:
jobs: ci: runs-on: ubuntu-latest steps: - name: 等队列有空位再继续 uses: actions/github-script@v6 with: script: | const maxConcurrent = 3; // 改成你要的最大并行数 const workflowName = 'CI'; // 换成你的工作流名称,或者用文件路径比如`.github/workflows/ci.yml` // 查当前正在运行的同工作流任务 let runs = await github.rest.actions.listWorkflowRuns({ owner: context.repo.owner, repo: context.repo.repo, workflow_id: workflowName, status: 'in_progress', per_page: 100 }); // 排除当前这个任务本身 let runningCount = runs.data.workflow_runs.filter(run => run.id !== context.runId).length; console.log(`当前在跑的任务数: ${runningCount}, 最大并行数: ${maxConcurrent}`); // 没空位就循环等,每分钟查一次 while (runningCount >= maxConcurrent) { console.log('已经满负荷了,等1分钟再看看...'); await new Promise(resolve => setTimeout(resolve, 60000)); // 更新当前运行数 runs = await github.rest.actions.listWorkflowRuns({ owner: context.repo.owner, repo: context.repo.repo, workflow_id: workflowName, status: 'in_progress', per_page: 100 }); runningCount = runs.data.workflow_runs.filter(run => run.id !== context.runId).length; } github-token: ${{ secrets.GITHUB_TOKEN }} # 下面是你原来的CI步骤 - name: 拉代码 uses: actions/checkout@v4 # ...剩下的打包、测试之类的步骤
注意点:
- 默认的
GITHUB_TOKEN已经有权限查工作流状态,不用额外配置 - 等待间隔可以自己调,比如改成30秒
- 工作流名称要准确,或者直接用工作流文件的路径更靠谱
方案二:用第三方动作直接实现排队
社区有现成的动作softprops/turnstyle,基于Redis做分布式排队,用起来更省心:
jobs: ci: runs-on: ubuntu-latest steps: - name: 排队等空位 uses: softprops/turnstyle@v1 with: poll-interval-seconds: 60 max-concurrent: 3 # 设置最大并行数 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # 原来的CI步骤 - name: 拉代码 uses: actions/checkout@v4 # ...其他CI任务
这个动作会自动帮你维护队列,只要当前运行的任务数到了上限,新任务就会进入等待状态,等有任务跑完了再接着执行。
补充说明
- 原生的
concurrency只适合处理同一个PR/分支的重复任务去重,跨PR的全局排队它搞不定,所以必须用上面的方法 - 两种方案各有好坏:自定义脚本不用依赖外部服务,但要自己维护逻辑;第三方动作简单,但默认用公共Redis,在意安全性的话可以自己搭Redis服务
内容的提问来源于stack exchange,提问作者Fred
相关产品推荐
相关产品推荐

