尧图精选

Encore.ts Cron Jobs 定时任务实战指南:用声明式调度 API 构建周期任务

🕒 发布时间:2026/9/15 16:29:39 📁 来源:尧图网络
Encore.ts Cron Jobs 定时任务实战指南用声明式调度 API 构建周期任务【免费下载链接】encoreThe infrastructure platform for the intelligence era项目地址: https://gitcode.com/GitHub_Trending/encor/encore导读在构建后端应用时周期性任务如发送欢迎邮件、清理过期数据、定时同步报表是不可或缺的能力。Encore.ts 提供了声明式的Cron Jobs API位于encore.dev/cron包让你只需定义任务是什么、多久跑一次剩下的调度、监控与执行全部交给 Encore 基础设施托管无需维护任何独立的定时任务服务。读完本文你将掌握CronJob的完整配置every周期调度与scheduleCron 表达式调度、编译期校验规则、生产部署限制以及从源码层面理解 Encore 编译器如何解析和校验你的定时任务定义。什么是 Encore.ts Cron Jobs当你需要在应用中运行周期性、重复性的任务时Encore.ts 提供了一种完全声明式的方式。其核心模型非常简单在应用代码中定义一个CronJobEncore 会根据你指定的调度规则自动调用对应的 API 端点。这种设计带来了一个关键收益——零基础设施维护。你不需要自己搭建 cron 服务器、不需要编写守护进程、不需要处理任务分发Encore 全权负责 Cron Job 的调度scheduling、监控monitoring与执行execution。从 运行时类型定义 可以看到CronJob类的真实结构export class CronJob { public readonly name: string; public readonly cfg: CronJobConfig; constructor(name: string, cfg: CronJobConfig) { this.name name; this.cfg cfg; } } export type CronJobConfig { endpoint: () Promiseunknown; title?: string; } ({ every: DurationString } | { schedule: string });值得注意的关键事实CronJob在运行时只是一个数据载体它不包含任何调度逻辑——真正的调度由 Encore 平台在部署后接管。类型定义明确要求配置中必须提供endpoint且every与schedule二选一这由 TypeScript 联合类型{ every } | { schedule }静态保证同时编译器还会做进一步校验下文会展开。定义第一个 Cron Job定义一个 Cron Job 只需三步从encore.dev/cron导入CronJob把new CronJob(...)的结果赋值给一个顶层变量然后指定要调用的 API。以下是最基本的示例来自官方文档import { CronJob } from encore.dev/cron; import { api } from encore.dev/api; // Send a welcome email to everyone who signed up in the last two hours. const _ new CronJob(welcome-email, { title: Send welcome emails, every: 2h, endpoint: sendWelcomeEmail, }) // Emails everyone who signed up recently. // Its idempotent: it only sends a welcome email to each person once. export const sendWelcomeEmail api({}, async () { // Send welcome emails... });这段代码部署后Encore Cloud 会自动注册该 Cron Job并每两小时调用一次sendWelcomeEmailAPI。理解name参数唯一 IDnew CronJob的第一个参数welcome-email是你为这个 Cron Job 指定的唯一 ID。它承载着一个重要的工程语义如果你日后重构代码、把 Cron Job 的定义移动到另一个包packageEncore 正是靠这个 ID 来识别这还是同一个任务而不是一个新任务从而保持调度的连续性不会造成重复创建。一个更完整的定义形态结合上面的类型定义一个完整的 Cron Job 配置可以同时包含配置项类型必填说明name构造器第一参数string是Cron Job 全局唯一 ID重构时用于保持任务身份endpoint() Promiseunknown是被调度的 API 端点不能接受任何请求参数everyDurationString与schedule二选一按固定周期执行如2h、10mschedulestring与every二选一标准 5 字段 Cron 表达式用于更复杂的调度titlestring否在 Encore 仪表盘中显示的人类可读标题从 legacymeta 生成逻辑 看未设置时默认回退为nameDurationString 支持的时间格式every字段接受的是DurationString类型其完整定义位于 runtimes/js/encore.dev/types/mod.tstype durationUnit ns | µs | ms | s | m | h; type durationComponent ${number}${durationUnit};支持的合法形式包括单个时间分量10s、500ms、5m、1h两个连续分量1h30m两个空格分隔分量1h 30m不过请注意虽然DurationString允许秒s甚至毫秒ms、纳秒ns粒度但编译器会对every做额外限制见下文编译期校验实际可用的最小粒度是分钟。调度方式一every周期调度上面示例使用的是every字段它按固定周期执行任务每天从午夜UTC开始全天候around the clock按该间隔循环运行。必须整除 24 小时为了保证每次运行之间的延迟一致every使用的间隔必须能够整除 24 小时。例如10m✅ 合法24 小时 1440 分钟1440 / 10 144整除6h✅ 合法24 / 6 4整除7h❌ 不合法24 不能被 7 整除会导致每天的运行时刻漂移如果你尝试使用非法间隔Encore 编译器会在编译期直接报错并给出友好的错误提示而不是等到部署后才出问题。源码中的校验逻辑从编译器实现 tsparser/src/parser/resources/infra/cron.rs 可以看到every的完整校验链路let secs every.as_secs(); if secs % 60 ! 0 { return Err(every.span().parse_err(every must be a multiple of 60 seconds)); } let mins secs / 60; if mins (24 * 60) { return Err(every.span().parse_err(every must be at most 24 hours)); }校验规则可以总结为两点必须是 60 秒1 分钟的整数倍——秒级以下的间隔如30s会被编译期拒绝最多不能超过 24 小时。满足这两个约束后编译器将every归一化为每 N 分钟CronJobSchedule::Every(u32)再进入后续的元数据生成流程。进一步地在 legacymeta 序列化逻辑 中该调度会被编码为every:{mins}的字符串形式下发给运行时/云平台执行。调度方式二scheduleCron 表达式当需求超出固定周期所能表达的范围——比如每月 15 号凌晨 4 点运行、每周一早上 9 点运行——every就不够用了。此时应改用schedule字段Encore.ts 提供了完整的 Cron 表达式 支持。官方示例如下文档原文// Run the monthly accounting sync job at 4am (UTC) on the 15th day of each month. const _ new CronJob(accounting-sync, { title: Cron Job Example, schedule: 0 4 15 * *, endpoint: accountingSync, })5 字段格式与编译期验证Encore 的 Cron 表达式采用标准 5 字段格式分钟 小时 日(月) 月 星期。在 CronExpr 的解析实现 中编译器会执行两层校验字段数量校验表达式必须恰好包含 5 个字段否则报错invalid cron expression: must have exactly 5 fields (minute, hour, day of month, month, day of week), e.g. * * * * *.表达式合法性校验通过cron_parser库以当前 UTC 时间为基准进行解析验证任何非法字段都会在编译期被捕获并给出具体错误信息。这意味着一旦写错 Cron 表达式你会在encore build/ 部署流程的编译阶段就得到明确反馈而不是到云端运行时报错。使用 Cron Jobs 必须牢记的注意事项根据官方文档与源码实现以下约束直接决定你的任务能否正确运行本地开发与 Preview 环境不执行Cron Jobs 在本地开发encore run时不会运行在 Preview Environments 中同样不会执行。但你可以通过手动调用 API 来测试任务逻辑本身这是官方推荐的行为验证方式。Free Tier 调度限制在 Encore Cloud 上免费层Free Tier用户的 Cron Job 执行频率被限制为每小时最多一次且具体执行分钟会在该小时内随机化。如果需要更高频率的执行或需要精确指定执行分钟请考虑部署到自己的云环境或升级付费方案。公有与私有 API 均可使用endpoint不要求必须是公有 API私有 APIapi({ expose: false })等同样可以作为 Cron Job 的调度目标。必须幂等idempotent由于网络条件等原因Cron Job 指向的 API可能被多次调用因此端点实现必须保证幂等——重复执行不会产生重复副作用如重复发邮件、重复扣款。上文示例中sendWelcomeEmail的实现思路每人只发一次正是这一要求的典型实践。端点不能接收请求参数Cron Job 调用的 API 端点不允许声明任何请求参数因为调度器不会也无法提供这些参数。如果端点声明了必填参数编译器会阻止你将其用作 Cron Job 的endpoint。源码视角Encore 编译器如何解析 Cron Job要真正理解 Cron Jobs 的声明式背后发生了什么可以沿着编译器的解析链路走一遍。Encore.ts 的前端编译器Rust 实现在 tsparser/src/parser/resources/infra/cron.rs 中注册了名为cron的资源解析器ResourceParserpub const CRON_PARSER: ResourceParser ResourceParser { name: cron, interesting_pkgs: [PkgPath(encore.dev/cron)], run: |pass| { let names TrackedNames::new([(encore.dev/cron, CronJob)]); ... }, };整个解析流程分为四步匹配引用编译器扫描所有源码文件凡是从encore.dev/cron包引用了CronJob的地方都会被追踪解析配置对象通过DecodedCronJobConfig结构体提取endpoint、title、every、schedule字段并对every/schedule执行上文的二选一与取值范围校验解析端点引用使用类型检查器type checker将endpoint字段解析为实际的 API 对象resolve_obj解析失败会报出cannot resolve endpoint编译错误注册资源与绑定将Resource::CronJob加入资源列表并把CronJob变量与资源建立绑定关系BindKind::Create。解析完成后还有一层跨资源校验。在 tsparser/src/app/mod.rs 的validate_crons函数中编译器会检查所有 Cron Job 的name是否全局唯一if let Some(prev_span) seen.insert(cron.name.clone(), cron.span) { HANDLER.with(|handler| { handler .struct_span_err(cron.span, cron job with this name already defined) .span_note(prev_span, previously defined here) .emit(); }) }这印证了前文的结论name是任务的全局身份标识重复定义同名 Cron Job 会在编译期直接报错编译器还会贴心地用span_note指出之前定义的位置。最后legacymeta 生成阶段 会把CronJob资源序列化为平台可执行的元数据title缺省时用name兜底调度被编码为schedule:{expr}或every:{mins}两种形态端点被解析为服务包路径 端点名的限定名QualifiedName最终由 Encore 云平台据此注册并调度任务。监控与调试Encore Cloud 仪表盘部署后Encore Cloud 仪表盘通过Cron Jobs菜单项为所有环境提供 Cron Job 执行的统一监控与调试界面你可以查看每次调度的运行历史、耗时与结果。由于本地与 Preview 环境不执行 Cron Jobs仪表盘也是观察真实调度行为的主要窗口。一个完整的可参考实现是 Uptime 监控示例应用它使用一个 Cron Job 周期性地检查网站的在线状态——如果你需要定时轮询 幂等处理的真实业务范式该教程是很好的起点。小结Encore.ts 的 Cron Jobs 把定时任务这一传统上的运维难题压缩成了几行声明式代码用new CronJob(id, config)声明任务every周期须整除 24 小时或schedule5 字段 Cron 表达式二选一编译器在编译期完成全部校验间隔合法性与上限、Cron 表达式格式、every/schedule互斥、端点可解析性、任务 ID 全局唯一端点必须无请求参数且幂等支持公有与私有 API本地与 Preview 环境不执行Free Tier 每小时最多一次——高频或精确调度需部署到自有云或升级方案。这套模型的价值在于调度器是平台的职责而不是你的。你只需要专注写出幂等的任务逻辑Encore 负责让它在正确的时间、以正确的频率被可靠地调用。【免费下载链接】encoreThe infrastructure platform for the intelligence era项目地址: https://gitcode.com/GitHub_Trending/encor/encore创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →