用 Cloudflare Workers 免费档搭一个服务巡检机器人:定时触发、静默失败与告警的三处坑

举报
yd_225649965 发表于 2026/11/11 01:05:54 2026/11/11
【摘要】 用 Cloudflare Workers 免费档搭一个服务巡检机器人:定时触发、静默失败与告警的三处坑个人站、小服务最怕的不是挂了,而是挂了没人知道。租一台 VPS 跑巡检脚本要花钱、要保活;用 Cloudflare Workers 免费档搭一个巡检机器人,零服务器、零费用,定时触发、异常发邮件,十几分钟就能跑起来。但免费档有三处坑是文档里写明、新手最容易踩的:Cron Trigger 静默...

用 Cloudflare Workers 免费档搭一个服务巡检机器人:定时触发、静默失败与告警的三处坑

个人站、小服务最怕的不是挂了,而是挂了没人知道。租一台 VPS 跑巡检脚本要花钱、要保活;用 Cloudflare Workers 免费档搭一个巡检机器人,零服务器、零费用,定时触发、异常发邮件,十几分钟就能跑起来。但免费档有三处坑是文档里写明、新手最容易踩的:Cron Trigger 静默失败、CPU 只有 10 毫秒、cron 只认 UTC。本文按官方限额(Workers Limits 文档,2026 年 10 月 29 日更新)写具体做法。

一、免费档能干什么:先对齐限额

动手前先把数字对齐,避免搭完才发现超限:

每天 10 万次请求(UTC 零点重置),巡检一次只消耗几次请求,额度绰绰有余;每账号最多 5 个 Cron Trigger,单个 Worker 最多 3 个(免费档);单次触发 CPU 时间上限 10 毫秒——注意是 CPU 时间,不是总耗时;每次触发最多 50 个子请求(fetch、KV、D1 等合计);定时触发的 wall time 上限 15 分钟;cron 最小粒度 1 分钟,且只认 UTC,没有时区选项。

结论:巡检“每 5 分钟查一次自己的站,挂了发邮件”完全在免费档内;巡检几十个目标、每次跑几分钟重逻辑,就要拆分或升级付费档。

二、最小实现:一个 Worker + 一次 fetch

wrangler.toml:

name = "uptime-watchdog"
main = "src/index.js"
compatibility_date = "2026-05-24"

[triggers]
crons = ["*/5 * * * *"]

[[kv_namespaces]]
binding = "STATE"
id = "<你的 KV namespace id>"

src/index.js:每次触发 fetch 目标站,超时 8 秒,状态写 KV,失败发邮件:

const TARGETS = ["https://example.com", "https://api.example.com/health"];

export default {
  async scheduled(event, env, ctx) {
    ctx.waitUntil(this.check(env));
  },
  async check(env) {
    for (const url of TARGETS) {
      const ok = await this.probe(url);
      await env.STATE.put(`last:${url}`, JSON.stringify({ ok, at: Date.now() }));
      if (!ok) await this.alert(env, url);
    }
  },
  async probe(url) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(8000) });
      return res.ok;
    } catch {
      return false;
    }
  },
  async alert(env, url) {
    await fetch("https://api.resend.com/emails", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${env.RESEND_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        from: "watchdog@yourdomain.com",
        to: "you@example.com",
        subject: `巡检告警:${url} 不可达`,
        text: `${url} 在 ${new Date().toISOString()} 连续探测失败,请检查。`,
      }),
    });
  },
};

密钥不要写进代码,用 npx wrangler secret put RESEND_KEY 放进 Secrets。部署后 npx wrangler tail 看一次触发,确认 cron 真的跑起来了。

三、坑一:Cron Trigger 失败是静默的

这是最容易翻车的一点:Cron Trigger 没有自动重试,也没有失败告警。一次触发里抛了异常,这次运行就直接丢了,不会有人告诉你。官方文档和几篇实测文章都确认了这一点。

对策是给巡检本身再加一道“看门狗”:第一,每次触发成功都在 KV 里写一个心跳时间戳(上面代码的 last:<url> 就是);第二,另起一个触发频率更低的 Worker(或外部免费 cron 服务),每次只干一件事:读 KV 里的心跳时间戳,如果超过 15 分钟没更新,说明主巡检 Worker 已经死了,立刻发告警;第三,告警发送本身也要 try/catch,失败写 KV 留痕,不要让一次发信失败拖垮整轮巡检。

原则:没有自检的巡检等于没巡检。心跳 + 看门狗这两层缺一不可。

四、坑二:10 毫秒 CPU 不等于 10 毫秒总耗时

新手看到“单次 CPU 10 毫秒”常以为巡检跑不了:一次 fetch 往返就要几十上百毫秒。关键点是:网络 I/O 的等待时间不计入 CPU 时间,只有真正执行 JS 的时间才算。一次 fetch 等 3 秒,CPU 可能只花了零点几毫秒。

真正要小心的有两处:第一,50 个子请求上限:一次触发里 fetch、KV 读写、发邮件全算子请求。巡检目标一多就容易顶满。做法是控制目标数量(比如每 Worker 不超过 10 个目标),或把目标拆到多个 Worker、多个触发器;第二,15 分钟 wall time 是硬上限:AbortSignal.timeout 的超时要设得比它小得多(上面用 8 秒),单个目标挂起不能拖住整轮;多目标串行探测时,总耗时是各目标超时之和,目标一多就改并行 Promise.allSettled。

五、坑三:cron 只认 UTC,北京时间要自己换算

Cron Trigger 的表达式只认 UTC,没有时区选项。想让巡检在北京时间每天 9 点跑,表达式要写成 0 1 * * *(UTC 1 点),而不是 0 9 * * *。这处换算错一次,巡检就会跑错 8 小时。

做法:表达式旁边写注释标明北京时间,例如 crons = ["0 1 * * *"] # 北京时间 09:00;部署后看一次 wrangler tail 的触发时间戳,核对是不是你想要的那个北京时间;跨夏令时的地区更麻烦:UTC 没有夏令时,表达式不用跟着调,但你的“北京时间换算”在夏令时切换前后会变,最好固定用 UTC 思考。

六、验收清单:部署完先故意弄挂一次

巡检机器人上线当天做三件事:第一,wrangler tail 确认 cron 按预期时间触发了一次,KV 心跳时间戳在更新;第二,把一个目标地址临时改成不存在的域名,看告警邮件能不能在下一轮触发后收到;第三,停掉主 Worker 的触发器(Dashboard 里关掉一个 cron),看“看门狗”能不能在 15 分钟后报出“心跳过期”。

三条都通过,这个机器人才算真的在值班。否则它只是个部署成功页。

小结

Cloudflare Workers 免费档做巡检的核心就三句话:限额先对齐(10 万次/天、5 个触发器、10 毫秒 CPU、50 子请求、15 分钟 wall time);失败必须自检(心跳 + 看门狗,补上平台不给的重试与告警);时间按 UTC 写(北京时间自己换算,部署后用 tail 核对)。这三处都处理好,一个零成本的巡检机器人就能长期稳定跑下去。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。