Monorepo ETL 的 4 种 GitHub Actions 模式
从一个 monorepo 运行三个网站会带来问题。你会面临三个独立的 ETL 任务、三次内容重建和三条部署流水线。如果不进行协调,它们会发生冲突。
我花了六周时间测试调度方案以稳定这一设置。以下是我使用的四种模式。
1. 为 Cron 任务使用时间偏移 (Time Offsets)
同时运行所有 ETL 任务会导致失败。任务会竞争 API 速率限制。当 HuggingFace 或 GitHub 返回 429 错误时,运行就会失败。
我使用 30 分钟的时间偏移来防止这种情况。
- 任务一在 02:00 开始
- 任务二在 02:30 开始
- 任务三在 03:00 开始
三十分钟足以在下一个任务开始前完成一次繁重的拉取操作。这能保持日志整洁并防止 API 冲突。
2. 使用跳过标志 (Skip Flags) 来停止不必要的重建
每个 ETL 任务最后都会进行 Vercel 部署。当文章提交也触发重建时,问题就出现了。如果没有计划,每次文章更新都会强制所有三个网站进行重建。这会浪费构建分钟数。
我在 ETL 提交信息中使用 [skip publish-articles] 标签。
我在工作流中添加了一个步骤来检查此标志。如果存在该标签,工作流将跳过构建和部署步骤。这使得 ETL 流水线与文章流水线保持分离。
3. 使用路径过滤器 (Path Filters) 来针对特定网站
你并不希望一个网站的更新触发三次部署。我配置了每个网站的工作流,使其仅监听自己的文件夹和共享包 (shared packages) 文件夹。
示例逻辑:
- AI 工具网站仅监听
apps/ai-tools/ - OSS 网站仅监听
apps/oss-alternatives/
如果你更改了共享目录中的代码,所有网站都将重建。我接受这种权衡,因为共享代码的更改非常罕见。
4. 添加手动触发 (Manual Dispatch) 以实现控制
Cron 处理日常例行任务,手动触发处理其他一切。我使用 workflow_dispatch,以便我可以:
- 重新运行失败的 ETL 任务
- 在添加数据后强制刷新
- 进行空运行 (dry run) 以测试数据而不写入数据库
GitHub UI 会为这些选项显示一个下拉菜单。这可以防止拼写错误并使调试变得容易。
总结
这些模式并不复杂,但非常明确。我在仓库中保留了一个简单的 Markdown 文件来记录这些规则。这确保了我在添加新工作流时不会破坏现有系统。
