微信云开发部署与定时触发器运维
> 来源:2026-11-01/02 「情绪宝塔」访客追踪(track 聚合 + trackAggregateDaily 定时)实际施工踩坑汇总。每条都是实测结论,不是文档转述。
一、部署是否生效:唯一可信判据
cloudbaserc.json/config.json里的运行时、超时、内存都不作数。项目若一直用「微信开发者工具」提交,该文件从未被读取,线上实际值只在控制台里。禁止拿它当部署事实汇报。- 判据 = 控制台「最后更新时间」与本机文件 mtime 对比:
- 线上时间 晚于 本地 mtime ⇒ 已部署且是最新。
- 线上时间 早于 本地 mtime ⇒ 有未部署改动,必须重传。 - 控制台面板会先渲染空表头、数据异步填充。未加载完就断言"没配/不存在"是假事实,必须刷新复核。措辞用"未查到,请确认"。
二、「上传并部署」三个选项
| 选项 | 何时用 | 备注 |
|---|---|---|
| 上传并部署:所有文件 | 本地有 node_modules |
无 node_modules 时会弹「云函数中有以下未安装的依赖…是否确认上传?」 |
| 上传并部署:云端安装依赖(不上传 node_modules) | 本地无 node_modules(最常见) | 云端装依赖,最稳,推荐默认 |
| 上传触发器 | 触发器有改动/首次创建 | 与代码部署是两条独立动作 |
要点:
- 部署代码不会删除已存在的触发器,不必重传触发器。
- 弹「未安装依赖」确认框时,点「取消」改走「云端安装依赖」更保险(避免全量上传把云端 node_modules 顶掉)。
- 部署成功要看到「云函数上传成功」,不要切走等。
三、定时触发器:在哪建
- 触发器声明在
cloudfunctions/<fn>/config.json:
json { "triggers": [ { "name": "trackAggregateDaily", "type": "timer", "config": "0 30 4 * * * *" } ] }
cron 为 7 段(秒 分 时 日 月 周 年),北京时间。控制台展示时可能省略末尾年字段。 - 创建入口只有一个:微信开发者工具 → 云函数目录右键 → 「上传触发器」。
- 网页控制台(tcb.cloud.tencent.com)触发器配置页只支持查看和删除,没有新建按钮,页面原文会写明"完整功能请在微信开发者工具中操作"。
- 触发器列表里的「删除」是删触发器本身,不是"清理多余项",别顺手点。
四、🔴 定时跑起来却"等于没跑"的坑(最高频)
定时触发器下发的事件体是:
{ "Type": "Timer", "TriggerName": "trackAggregateDaily", "Time": "2026-11-02T04:30:00Z" }
没有 action 字段。 若云函数入口写成:
const action = event && event.action ? event.action : 'report' // ❌
那么定时任务会走 report 分支 —— 而 report 通常要校验 OPENID,定时调用必然无 OPENID ⇒ 直接返回 {code:401},每天准时跑、每次秒退、日志里只有一条 401,聚合表永远不新增数据,且不会有人发现。
正确写法(先识别 Timer,再定默认动作):
const isTimer = !!(event && (event.Type === 'Timer' || event.TriggerName))
const action = event && event.action ? event.action : (isTimer ? 'aggregate' : 'report')
配套:聚合类 action 应加"有 OPENID 就拒绝(403)"的反向保护,防止小程序端直接调用定时专用分支。这层保护也挡住了前端伪造 {"Type":"Timer"} 的空子。
五、一条命令验证「部署 + 路由」
不用等到凌晨四点。控制台 → 云函数 → 目标函数 → 「函数代码」tab → 右上角「测试」 → 右侧面板替换事件 JSON:
{"Type":"Timer","TriggerName":"trackAggregateDaily"}
点「运行测试」,据返回判定:
| 返回 | 结论 |
|---|---|
code:0 + 业务字段(如 date:"2026-11-01") |
线上已是新代码,定时链路通 |
code:401 缺少身份、耗时 1ms |
线上仍是旧代码(未识别 Timer),需重新部署 |
code:403 |
从带 OPENID 的环境调用,event 被前端触发 |
这个手法同时干了两件事:确认代码版本、确认定时事件能命中正确分支。比"看控制台时间戳"更硬。
面板细节:事件编辑器默认塞的是 {"name":"test",...} Hello World 模板,全选替换即可;上方模板下拉框不用管。
六、聚合表幂等与补跑
- 用
doc(日期字符串).set()做 upsert(_id即日期),补跑与定时跑都写同一行,不产生重复。 - 记录里加
backfilled布尔(是否手传date)区分"按时跑的"和"事后补的";updatedAt只记写入时刻,补跑会盖成今天,光看它分不清。 - 补跑护栏(缺一条就会把好数据抹掉):
- 超出明细保留期直接拒绝,不能只 warn 继续跑 —— 明细已被裁剪、读到 0 条,再
set就把历史正确的行覆盖成全 0。 - 读到 0 条时先
doc(date).get()查有无既有记录,有则拒绝覆盖。 - 回看型指标(如回流/召回,要看历史窗口)在窗口被裁掉时应写
-1+reliable:false,不要写一个虚高的正数。
七、超时
云函数默认超时 20 秒(控制台「配置」里改,可到 60 秒)。全量扫表的聚合函数务必先改再压测,否则大环境直接 20 秒掐断,表现为"偶发失败"。
八、施工后自检清单
- [ ] 云函数改动:
node --check过、备份到tools/backup/、重新部署、记下控制台新时间戳 - [ ] 定时触发器:
config.json有声明 + 开发者工具「上传触发器」 + 控制台列表能看到 - [ ] 用
{"Type":"Timer","TriggerName":"..."}云端测试一次,返回code:0 - [ ] 目标表出现预期日期那一行,
backfilled/sample与手工对账一致 - [ ] CRLF 文件(
project.config.json、云函数index.js若为 CRLF)禁用 Edit,改完校验「裸 LF = 0」