` 定时清理数据(附示例应用源码解析))
Convex Cron Jobs 实战指南用cronJobs()定时清理数据附示例应用源码解析【免费下载链接】convex-backendThe open-source reactive database for app developers项目地址: https://gitcode.com/gh_mirrors/co/convex-backend本指南围绕开源仓库 convex-backend 中的npm-packages/demos/cron-jobs示例应用展开讲解如何在 Convex 中使用内置的 cron 定时任务能力每间隔一段时间自动执行 mutation 或 action例如每分钟清空一次消息表。读完本文你将掌握cronJobs()的完整用法、五种调度方式interval/hourly/daily/weekly/monthly/cron字符串的参数规则并理解从客户端配置到服务端执行的完整链路。示例应用概览每 60 秒清空一次消息表npm-packages/demos/cron-jobs是一个基于 Vite React 的最小示例它构建在仓库中的 Convex tutorial 教程示例 之上只多了一样东西——cron 定时任务。它的行为非常直观用户在聊天界面发送消息消息写入messages表一个每 1 分钟触发一次的 cron 任务将messages表清空。前端界面上也明确写出了提示Messages will be cleared every minute消息每分钟会被清空见 App.tsx。也就是说这是一个用完即清的演示既能验证定时任务的触发又能避免演示数据无限堆积。快速运行示例应用使用 pnpm workspace 管理依赖convex以workspace:*形式引入见 package.json。在npm-packages/demos/cron-jobs目录下执行npm install npm run dev其中dev脚本实际执行的是convex dev --start vite --open见 package.json。这条命令会同时做两件事启动 Convex 本地开发后端监听convex/目录下的函数文件热重载部署启动 Vite 开发服务器并自动打开浏览器。当convex/crons.ts被部署后cron 调度器即开始生效——按文档说明interval 类任务从首次部署到 Convex 时开始计时源码注释见 cron.ts。核心代码逐行拆解1. 定义 cron 任务convex/crons.ts示例的定时任务定义在 crons.tsimport { cronJobs } from convex/server; import { internal } from ./_generated/api; const crons cronJobs(); crons.interval( clear messages table, { minutes: 1 }, internal.messages.clearAll, ); export default crons;关键点cronJobs()从convex/server导入返回一个Crons实例cron.ts第一个参数clear messages table是唯一标识符cron identifier源码规定必须是可打印 ASCII 字符/^[ -~]*$/且同一个文件中不允许重复注册否则会抛出Cron identifier registered twice: ...cron.ts第二个参数{ minutes: 1 }是调度配置第三个参数internal.messages.clearAll是要执行的函数引用——这里使用的是internal 函数下文详述文件必须export default cronsConvex 后端才会识别并注册这些定时任务。2. 定时执行的函数convex/messages.ts被 cron 调用的clearAll定义在 messages.tsexport const clearAll internalMutation({ args: {}, handler: async (ctx) { for (const message of await ctx.db.query(messages).collect()) { await ctx.db.delete(messages, message._id); } }, });同文件还定义了聊天功能本身需要的两个函数export const list query({ args: {}, handler: async (ctx) { return await ctx.db.query(messages).collect(); }, }); export const send mutation({ args: { body: v.string(), author: v.string(), }, handler: async (ctx, { body, author }) { const message { body, author }; await ctx.db.insert(messages, message); }, });这里有一个值得注意的设计cron 调用的clearAll用的是internalMutation而非普通mutation。internal 函数不能被客户端直接调用只能由服务端其他函数、scheduler、cron调用因此用于清理类任务更安全——用户无法通过 HTTP 端点绕过前端逻辑直接触发它。这也解释了为什么crons.ts中引用的是internal.messages.clearAll而不是api.messages.clearAll。3. 前端src/App.tsxApp.tsx 使用convex/react的useQuery/useMutation订阅api.messages.list和api.messages.sendconst messages useQuery(api.messages.list) || []; const sendMessage useMutation(api.messages.send);每当 cron 清空表后useQuery会自动收到新的查询结果消息列表随之变为空——不需要任何手动刷新。这也是观察 cron 是否生效的最直接方式发送几条消息等一分钟列表被清空。深入convex/server的cronJobs()实现cronJobs()的完整实现位于 npm-packages/convex/src/server/cron.ts。Crons类内部维护一个Recordstring, CronJob每次调用schedule()都会做三件事解析参数、校验标识符唯一性、把{ name, args, schedule }存入crons表cron.ts。六种调度方式与参数校验方法调度配置参数要求crons.interval(id, schedule, fn){ seconds }/{ minutes }/{ hours }三选一必须且只能指定其中一个值为正整数cron.tscrons.hourly(id, schedule?, fn){ minuteUTC?: 0-59 }可整体省略省略minuteUTC时由后端在整点内随机分摊避免所有任务挤在整点cron.tscrons.daily(id, schedule, fn){ hourUTC: 0-23, minuteUTC?: 0-59 }hourUTC必填且为 UTC 小时cron.tscrons.weekly(id, schedule, fn){ dayOfWeek: monday...sunday, hourUTC, minuteUTC? }星期必须是英文小写全称cron.tscrons.monthly(id, schedule, fn){ day: 1-31, hourUTC, minuteUTC? }注意大于 28 的日期在部分月份不会触发例如 30 号在二月不运行cron.tscrons.cron(id, cronString, fn)标准 5 段 cron 表达式字段依次为分钟(0-59)、小时(0-23)、日(1-31)、月(1-12)、星期(0-6周日为 0)如15 7 * * *表示每天 7:15 UTCcron.ts所有字段都在注册时进行严格校验非法值会直接抛出Error。例如间隔不是正整数 →Interval must be an integer greater than 0小时超出 0-23 →Hour of day must be an integer from 0 to 23星期名拼写错误 →Day of week must be a string like monday.更多调度示例// 每 30 秒运行一次 crons.interval(cleanup, { seconds: 30 }, api.jobs.cleanup); // 每小时的 30 分运行UTC crons.hourly(reset scores, { minuteUTC: 30 }, api.scores.reset); // 每天 17:30 UTC 运行 crons.daily(digest, { hourUTC: 17, minuteUTC: 30 }, api.emails.sendDailyDigest); // 每周二 17:30 UTC 运行 crons.weekly( weekly email, { dayOfWeek: tuesday, hourUTC: 17, minuteUTC: 30 }, api.emails.send, ); // 每月 1 号 17:30 UTC 运行 crons.monthly( bill customers, { day: 1, hourUTC: 17, minuteUTC: 30 }, api.billing.billCustomers, ); // 标准 cron 表达式每天 7:15 UTC crons.cron(backup, 15 7 * * *, api.jobs.backup);interval、daily、weekly、monthly、cron都支持在函数引用后追加位置参数...args这些参数会被parseArgs解析并序列化为 JSON 传给目标函数cron.ts。服务端如何执行 cron 任务前端 SDK 的crons.ts只是配置真正把配置变成周期性执行的是 Rust 后端。定时任务的调度与执行逻辑位于 crates/application/src/cron_jobs/mod.rs其中引用了model::cron_jobs模块的compute_next_ts、stream_cron_jobs_to_run等核心函数以及CronJob、CronJobState、CronJobStatus、CronNextRun等类型负责计算每个任务的下一次执行时间戳并按序触发触发时以InertIdentity无用户身份的系统身份执行目标 UDF并受SCHEDULED_JOB_EXECUTION_PARALLELISM定时任务执行并行度等 knobs 控制mod.rs任务执行结果会记录CronJobResult与CronJobLogLines便于在 Convex 仪表盘中查看每次运行的日志。也就是说客户端crons.ts里写的{ minutes: 1 }这类配置最终会被后端持久化为带类型标签的调度计划{ type: interval, minutes: 1 }再由compute_next_ts依据当前时间计算出下一次执行时刻并排队执行。排查与注意事项确认任务已注册crons.ts必须export default crons且标识符不能重复否则部署时报错区分 internal 与 publiccron 可以调用 public 的mutation/action也可以调用internalMutation/internalAction示例选择 internal 是为了防止用户直接触发清理逻辑UTC 时区hourUTC、minuteUTC以及 cron 表达式均以UTC为准配置前需要把本地时区换算为 UTC避免任务在错误的时间触发cron.ts每月大日期陷阱monthly的day若大于 28并非每个月都会运行首跳时间interval 任务从部署时刻起算因此间隔是相对部署时间的而非对齐到整点。小结通过npm-packages/demos/cron-jobs这个极简示例可以看到 Convex cron 的完整工作模式convex/crons.ts集中声明调度计划 → SDK 校验并序列化 → Rust 后端cron_jobs模块按compute_next_ts计算的下一次时间触发 → 目标函数以系统身份执行并记录日志。从每分钟清空消息表的玩具示例出发你完全可以把它扩展为数据清理、定时报表、邮件提醒、缓存刷新等生产级定时任务。【免费下载链接】convex-backendThe open-source reactive database for app developers项目地址: https://gitcode.com/gh_mirrors/co/convex-backend创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考