TensorFlow.js 夜间构建自动化实战:解读 tfjs 仓库的 Google Cloud Functions CI 流水线

发布时间:2026/9/21 0:00:52
TensorFlow.js 夜间构建自动化实战:解读 tfjs 仓库的 Google Cloud Functions CI 流水线 人工智能机器学习深度学习前端后端【免费下载链接】tfjsA WebGL accelerated JavaScript library for training and deploying ML models.项目地址https://gitcode.com/gh_mirrors/tf/tfjs点击查看免费下载导读本文以 tfjs-core/scripts/cloud_funcs/README.md 为核心系统讲解 TensorFlow.js 仓库如何借助 Google Cloud Functions、Cloud Scheduler、Cloud Build 与 Pub/Sub Topic 构建夜间自动构建 结果通知 跨平台测试同步的完整 CI 流水线。你将掌握trigger_nightly、send_email、sync_reactnative三个云函数的职责分工、底层调用链与重新部署命令并学会如何通过 substitution 变量、环境变量与 KMS 密钥管理让这套流水线安全落地到自己的项目。背景为什么要用云函数编排夜间构建TensorFlow.js 是一个大型 monorepo包含 tfjs-core、tfjs-layers、tfjs-converter、tfjs-node 等众多子包日常开发中 PR 触发的普通构建与每日凌晨的全量回归构建需求完全不同夜间构建需要每天定时在 master 分支上运行一次全量测试验证当天合并的代码是否引入回归结果通知需要把构建结果成功/失败/超时第一时间送达内部邮件列表与聊天群方便开发者次日上班前就知晓状态跨平台同步需要定期把 React Native 集成测试包同步到 BrowserStack 云真机平台防止测试包过期失效。直接写一个常驻服务来做这些事既不经济也不利于运维。TensorFlow.js 的选择是把每个环节拆成独立的 Google Cloud Functions由 Cloud Scheduler 定时触发、由 Pub/Sub Topic 串联消息形成松耦合、可单独重部署的流水线。在仓库中云函数的部署说明有两份本文重点解读的 tfjs-core/scripts/cloud_funcs/README.md早期版本运行时为 nodejs8以及仓库根目录下内容更新的 scripts/cloud_funcs/README.md运行时已升级为 nodejs14函数名改为nightly_tfjs。两版逻辑一致本文以关联文档为主干同时用新版实现补充细节。云函数一trigger_nightly —— 程序化触发 master 构建职责与触发方式trigger_nightly的作用是程序化地触发 Cloud Build 在 master 分支上执行构建。它本身由 Cloud Scheduler 每天凌晨定时调用时间可在 Cloud Scheduler 控制台配置两版文档记录的默认时间不同早期文档为每天 3:00 EST新版文档为每天 4:00 America/New_York均可通过 Scheduler UI 调整。此外你也可以通过 Cloud 控制台手动触发该函数用于临时补跑夜间构建。重新部署命令关联文档给出了完整的部署命令gcloud functions deploy nightly \ --runtime nodejs8 \ --trigger-topic nightly各参数含义如下参数说明nightly部署后的云函数名称新版文档中为nightly_tfjs与 Pub/Sub topic 同名--runtime nodejs8函数运行时版本。注意关联文档使用的是当时推荐的 nodejs8而仓库根目录的新版文档已更新为--runtime nodejs14实际部署时应以 GCP 当前支持的运行时为准--trigger-topic nightly将该函数订阅到名为nightly的 Pub/Sub topic 上Cloud Scheduler 往这个 topic 写消息即可触发函数源码级调用链从实现来看见 scripts/cloud_funcs/trigger_nightly/index.js函数体非常简洁核心逻辑只有三步通过googleapis的google.cloudbuild(v1)获取 Cloud Build API 客户端用google.auth.getClient申请cloud-platform范围的凭据并注入到全局google.options({auth})调用cloudbuild.projects.triggers.run携带固定的projectIdlearnjs-174218、triggerId43c56710-ccb3-4db9-b746-603cffbf0c02以及branchName: master让 Cloud Build 构建触发器在 master 分支上跑一次。这段代码的依赖声明在 scripts/cloud_funcs/trigger_nightly/package.json 中仅需要googleapis一个运行时依赖体现了函数越小越易维护的设计。关键衔接点substitution 变量_NIGHTLY这是整套流水线中最值得借鉴的衔接机制。当构建由夜间任务触发时Cloud Build 中会存在 substitution 变量_NIGHTLYtrue。为了让构建脚本感知到这是一次夜间构建需要在cloudbuild.yml中把它转发为环境变量env: [NIGHTLY$_NIGHTLY]在 e2e 测试的构建配置中可以看到这一模式的真实用法例如 e2e/cloudbuild.yml 与 e2e/benchmarks/browserstack-benchmark/cloudbuild.yml 均包含env: [BROWSERSTACK_USERNAMEdeeplearnjs1, NIGHTLY$_NIGHTLY]并在substitutions中预置_NIGHTLY: 作为默认值如 e2e/cloudbuild.yml。下游脚本拿到NIGHTLY后据此调整行为。例如 e2e/scripts/test.sh 中if [[ $NIGHTLY true ]]; then分支会在夜间构建时执行额外逻辑e2e/scripts/build-deps-ci.sh 也会在NIGHTLY或RELEASE为 true 时执行更重的依赖构建。这一触发器传参 → 构建配置转发 → 脚本分叉的链路是让同一套 CI 配置同时服务 PR 构建与夜间构建的关键。云函数二send_email —— 夜间构建结果通知职责与订阅方式send_email负责把夜间构建的状态通过邮件与聊天消息发出。它的数据来源不是 Cloud Scheduler而是 Cloud Build 本身每次构建结束Cloud Build 都会把包含构建信息的消息写入cloud-buildstopicsend_email就订阅在这个 topic 上监听所有构建消息。因此它必须做两层过滤只关心夜间构建状态过滤只处理SUCCESS、FAILURE、INTERNAL_ERROR、TIMEOUT、CANCELLED、FAILED等已知终止状态忽略进行中的构建触发器过滤只处理buildTriggerId等于夜间触发器 ID43c56710-ccb3-4db9-b746-603cffbf0c02的构建从而把 PR 触发的普通构建排除在外。默认在凌晨 3:10 左右新版文档为 4:40 左右把夜间构建状态发送到内部邮件列表实际发送时机由构建结束时间决定。重新部署命令gcloud functions deploy send_email \ --runtime nodejs8 \ --stage-bucket learnjs-174218_cloudbuild \ --trigger-topic cloud-builds \ --set-env-vars MAILGUN_API_KEY[API_KEY_HERE],HANGOUTS_URL[URL_HERE]参数要点参数说明--stage-bucket learnjs-174218_cloudbuild函数代码的暂存 GCS bucket部署时源码会上传到该 bucket--trigger-topic cloud-builds订阅 Cloud Build 自动发布的构建事件 topic--set-env-vars MAILGUN_API_KEY...,HANGOUTS_URL...注入运行时环境变量Mailgun API Key发邮件用与 Hangouts 聊天机器人 Webhook 地址。新版部署时需替换为--runtime nodejs14源码级实现细节见 scripts/cloud_funcs/send_email/index.js。函数入口module.exports.send_email async event {...}接收 Pub/Sub 消息关键处理逻辑为const build JSON.parse(Buffer.from(event.data, base64).toString());即把 Pub/Sub 消息的 base64 数据解码后反序列化出 Cloud Build 构建对象。随后按上文所述的状态列表与buildTriggerId双重过滤。通过后用humanize-duration库根据build.startTime与build.finishTime计算构建耗时拼装消息文本例如tfjs nightly finished with status FAILURE, in 25 minutes.消息中还会带上build.logUrl日志链接。值得注意的一个趣味细节构建失败时sendChatMsg会向第三方笑话 API 请求一条随机笑话附在消息后缓解失败带来的沮丧感见 send_email/index.js。消息最终通过requestPOST 到process.env.HANGOUTS_URL指向的 Webhook。该函数的依赖清单humanize-duration、node-fetch、request、request-promise-native见 scripts/cloud_funcs/send_email/package.json。从源码看当前版本实现中聊天通知是明确落地的邮件发送依赖部署时注入的MAILGUN_API_KEY环境变量与外部邮件服务协作README 描述其同时发送邮件与聊天消息。云函数三sync_reactnative —— 定时同步 React Native 测试包到 BrowserStack职责与背景TensorFlow.js 的 React Native 集成测试在 BrowserStack 云真机上运行而BrowserStack 要求上传的 App 至少每 30 天重新同步一次否则会过期失效。sync_reactnative专门解决这个问题它从 GCP bucket 拉取 tfjs-react-native 集成测试 App 的当前构建上传到 BrowserStack并通过custom_id覆盖更新同名 App。触发方式同样是 Cloud Scheduler 通过sync_reactnativetopic 调用当前配置为每周四凌晨 3:00 运行一次留足了低于 30 天阈值的余量。这个触发节奏在关联文档中有明确说明。重新部署命令gcloud functions deploy sync_reactnative \ --runtime nodejs8 \ --trigger-topic sync_reactnative \ --set-env-vars HANGOUTS_URL[URL_HERE],BOTS_HANGOUTS_URL[URL_HERE]与前面两个函数不同它注入了两个聊天 Webhook 环境变量环境变量用途HANGOUTS_URL同步失败时发送告警的聊天地址BOTS_HANGOUTS_URL同步成功时发送确认消息的机器人地址源码级实现细节见 scripts/cloud_funcs/sync_reactnative/index.js。这个函数最能体现敏感信息如何安全落地到云函数的实践KMS 解密BrowserStack 的 API Key 不以明文形式出现在代码或环境变量中而是先加密成一段 ciphertext 硬编码在源码里。运行时通过google-cloud/kms的KeyManagementServiceClient按projectIdlearnjs-174218、locationIdglobal、keyRingIdtfjs、cryptoKeyIdenc定位密钥并调用decrypt还原出明文 key见 sync_reactnative/index.js。上传 BrowserStack携带deeplearnjs1用户名与解密后的 key向 BrowserStack 的app-automate/upload接口发起带 Basic Auth 的 POST 请求表单数据为{url: https://storage.googleapis.com/tfjs-rn/integration-tests/app-debug.apk, custom_id: tfjs-rn-integration-android}即让 BrowserStack 直接抓取 GCP bucket 中的 APK 并覆盖更新指定 ID 的测试包。结果分叉通知成功时向BOTS_HANGOUTS_URL发送成功消息失败时捕获异常并记录日志同时向HANGOUTS_URL发送错误告警。该函数依赖google-cloud/kms、google-cloud/functions-framework、request、request-promise-native见 scripts/cloud_funcs/sync_reactnative/package.json。其中google-cloud/functions-framework提供了本地调试入口在包目录执行npm start对应functions-framework --targetsync_reactnative即可在本机起一个 HTTP 服务模拟云函数运行时极大方便了部署前的联调。完整流水线四个环节如何串联关联文档用最精炼的方式给出了整条流水线定时触发凌晨 3 点Cloud Scheduler 向nightlytopic 写入消息新版为nightly_tfjstopic启动构建消息触发trigger_nightly函数函数调用 Cloud Build API 在 master 分支上程序化启动一次构建回传状态构建运行结束后Cloud Build 自动把状态消息写入cloud-buildstopic通知结果send_email函数被该 topic 触发过滤出夜间构建后把成功/失败状态通过邮件与聊天消息发出。在这条链路上sync_reactnative是相对独立的旁路——它不与夜间构建直接耦合而是按周单独调度保证 BrowserStack 上的集成测试 App 永远处于有效期内。实践要点与前提说明从这套 CI 设计中可以提炼出几条直接可复用的经验用 Pub/Sub topic 解耦触发与执行Cloud Scheduler 只负责写消息函数只负责响应消息任何一环都可以单独重部署而不影响其他环节这也是三个函数全部支持独立gcloud functions deploy的原因。用 substitution 变量打通触发原因_NIGHTLYtrue这种约定让下游脚本如 e2e/scripts/test.sh能区分夜间构建与 PR 构建在夜间跑更全量的测试。用 KMS 托管敏感凭据BrowserStack key 以密文形式内联运行时解密避免把明文密钥写进仓库或环境变量。运行时版本需要与时俱进关联文档记录的部署命令使用 nodejs8 运行时而仓库根目录的更新版 README 已迁移到 nodejs14函数名同步改为nightly_tfjs。如果你要复刻这套流水线请以 GCP 当前支持的 Node.js 运行时为准并注意函数名、topic 名与 triggerId 都要与自己的 Cloud Build 触发器一一对应。需要说明的前提上述部署命令依赖 Google Cloud Platform 账号、已创建好的 Pub/Sub topicnightly/nightly_tfjs、cloud-builds、sync_reactnative、Cloud Build 触发器示例中的triggerId属于 tfjs 项目的learnjs-174218项目以及 Mailgun、Hangouts、BrowserStack 等外部服务的有效凭据——这些资源无法从本仓库直接获得读者在自己的 GCP 项目中复刻时需要替换为对应的资源标识与密钥。延伸阅读云函数三件套的完整源码与依赖清单scripts/cloud_funcs/trigger_nightly/、scripts/cloud_funcs/send_email/、scripts/cloud_funcs/sync_reactnative/更新版本的部署说明nodejs14 运行时scripts/cloud_funcs/README.md_NIGHTLYsubstitution 变量在构建配置中的转发示例e2e/cloudbuild.yml、e2e/benchmarks/browserstack-benchmark/cloudbuild.yml夜间构建标志在下游脚本中的消费逻辑e2e/scripts/test.sh、e2e/scripts/build-deps-ci.sh赞分享人工智能机器学习深度学习前端后端【免费下载链接】tfjsA WebGL accelerated JavaScript library for training and deploying ML models.项目地址https://gitcode.com/gh_mirrors/tf/tfjs点击查看免费下载相关推荐tfjs-converter 夜间测试自动化Cloud Scheduler Cloud Functions Cloud Build 流水线深度解析tfjs converter 夜间测试自动化Cloud Scheduler Cloud Functions Cloud Build 流水线深度解析 导人工智能机器学习深度学习前端后端Matterconnectedhomeip持续构建实战基于 Google Cloud Build 的 SDK 自动化编译流水线Matterconnectedhomeip持续构建实战基于 Google Cloud Build 的 SDK 自动化编译流水线 本篇文章以 integra物联网智能家居嵌入式通信music-website CI/CD流水线自动化构建与部署实战music website CI/CD流水线自动化构建与部署实战 想要快速掌握现代化音乐网站项目的持续集成与持续部署技巧吗本文将为你揭秘music webs后端前端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考