ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Midway 2.0 定时任务触发器(Timer Trigger)实战:cron 与 every 两种定时方式详解

Midway 2.0 定时任务触发器(Timer Trigger)实战:cron 与 every 两种定时方式详解 后端微服务云原生【免费下载链接】midway A Node.js Serverless Framework for front-end/full-stack developers. Build the application for next decade. Works on AWS, Alibaba Cloud, Tencent Cloud and traditional VM/Container. Super easy integrate with React and Vue. 项目地址https://gitcode.com/gh_mirrors/mi/midway点击查看免费下载在 Serverless 架构下定时任务是最常见的业务场景之一每天凌晨清理缓存、每隔几分钟同步数据、定时生成报表等。Midway 2.0 提供了一套基于装饰器的统一触发模型其中Timer 触发器定时任务触发器用于按固定时间间隔every或 cron 表达式定时执行一个函数。本文将以阿里云函数计算FC为例完整讲解 Timer 触发器的定义方式、配置参数、事件结构、本地测试方法以及成本规避建议帮助你在项目中直接落地可运行的定时函数。认识 Timer 触发器两种定时方式定时任务触发器用于定时执行一个函数Midway 2.0 在函数类方法上通过ServerlessTrigger(ServerlessTriggerType.TIMER, {...})来声明。定时方式有两种every固定时间间隔按分钟粒度固定间隔触发例如每 5 分钟执行一次croncron 表达式使用标准的 7 段 cron 表达式精确控制触发时刻例如每天凌晨 4 点执行。从源码看ServerlessTriggerType.TIMER对应枚举值timer定义在 packages/core/src/interface.ts#L295-L308export enum ServerlessTriggerType { EVENT event, HTTP http, API_GATEWAY apigw, OS os, CDN cdn, LOG log, TIMER timer, MQ mq, KAFKA kafka, HSF hsf, MTOP mtop, SSR ssr, }同时TimerTriggerOptions接口packages/core/src/interface.ts#L251-L256对 TIMER 触发器的元数据做了类型约束export interface TimerTriggerOptions extends TriggerCommonOptions { type: cron | every | interval; value: string; payload?: string; enable?: boolean; }可以看到类型层面还保留了interval这一取值配合可选字段payload固定传递值与enable是否启用触发器这些在部署生成触发器配置时会被整体透传给平台。快速上手为函数挂载 Timer 触发器在函数类中使用ServerlessTrigger装饰器即可声明一个定时触发的方法完整示例如下import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from midwayjs/decorator; import { Context, FC } from midwayjs/faas; Provide() export class HelloAliyunService { Inject() ctx: Context; ServerlessTrigger(ServerlessTriggerType.TIMER, { type: cron, value: 0 0 4 * * *, // 每天4:00触发 }) async handleTimerEvent(event: FC.TimerEvent) { this.ctx.logger.info(event); return hello world; } }关键点说明Provide()将类注册为依赖注入容器中的服务保证函数实例可被框架正常创建和调用Inject() ctx: Context注入函数计算上下文对象可通过this.ctx.logger输出运行日志ServerlessTrigger(ServerlessTriggerType.TIMER, {...})声明该方法为 TIMER 触发器第二个参数即触发器配置type value方法参数event: FC.TimerEvent接收平台传入的定时事件结构类型定义由midwayjs/faas提供。从装饰器实现看packages/core/src/decorator/faas/serverlessTrigger.ts#L61-L85ServerlessTrigger会将type、methodName以及你传入的metadata即{ type: cron, value: 0 0 4 * * * }这类配置一起写入类的元数据供部署时解析并生成平台侧的触发器定义MetadataManager.attachMetadata( FUNC_KEY, { type, methodName: functionName, metadata, }, target );也就是说装饰器配置会原样进入元数据管道最终映射为 FC 平台的 Timer 触发器。编写完成后执行npm run deploy即可将函数与触发器一并部署上线平台到点会自动触发该方法。Timer 配置参数详解Timer 触发器的配置项如下表所示属性名类型必填描述typecron/every是触发类型分别代表 cron 表达式与固定时间间隔valuestring是cron 表达式或 every 间隔值every 方式最小时间间隔为 1 分钟固定以分钟为单位payloadstring否一个固定传递的值使用频率很低可选此外类型定义中还有可选的enable布尔字段是否启用触发器在需要动态开关时可以在元数据中配置。cron 表达式示例ServerlessTrigger(ServerlessTriggerType.TIMER, { type: cron, value: 0 0 4 * * *, // 每天4:00触发 })cron 表达式为标准的 7 段格式秒、分、时、日、月、周、年可用*、,、-、/等符号组合精确的触发时刻适合「每天固定时间」「每周几执行」这类场景。every 表达式示例ServerlessTrigger(ServerlessTriggerType.TIMER, { type: every, value: 5m, // 每隔 5 分钟最小为 1 分钟 })every 方式直接写分钟数并带m后缀例如5m表示每 5 分钟触发一次。注意最小时间间隔为 1 分钟即1m是最小合法值。every 适合「周期性轮询」「持续同步」这类场景。时区提醒FC 使用 UTC 时间⚠️ 特别提醒阿里云函数计算使用的是UTC 时间与传统的中国时区UTC8不同。因此配置 cron 表达式时需要将目标时刻换算成 UTC。例如希望北京时间每天 12:00 触发cron 表达式应写成0 0 4 * * *UTC。换算错误是定时任务最常见的踩坑点。在仓库测试夹具 packages/core/test/fixtures/app-with-serverless-trigger/src/function/hello_aliyun.ts#L36-L47 中可以看到同一函数上挂载多个 TIMER 触发器的写法包括通过name: custom_timer自定义触发器名称以及 cron 与 every 两种 type 的混合使用可作为多定时器场景的参考ServerlessTrigger(ServerlessTriggerType.TIMER, { type: cron, // or every value: 0 0 4 * * *, // or 1m name: custom_timer, }) ServerlessTrigger(ServerlessTriggerType.TIMER, { type: cron, // or every value: 0 0 1 * * *, // or 1m }) async handleTimerEvent(event) { return hello world; }事件结构Timer 触发时平台会向函数传入如下结构的事件对象其类型在FC.TimerEvent中已有描述{ triggerTime: new Date().toJSON(), triggerName: timer, payload: , }字段含义triggerTime本次触发的 UTC 时间ISO 8601 字符串格式triggerName触发器名称默认值为timer可通过name配置自定义payload触发时携带的固定值即配置项payload的内容未配置时为空字符串。在业务方法中直接读取event即可拿到上述字段例如记录触发时间用于幂等或审计async handleTimerEvent(event: FC.TimerEvent) { this.ctx.logger.info(trigger at ${event.triggerTime}, payload ${event.payload}); // 执行定时业务逻辑 return ok; }本地开发与测试本地开发的限制事件类型的函数本地无法使用 dev 模式dev命令进行开发调试——因为定时触发由云端平台调度本地没有真实的触发源。取而代之的是通过npm run test以单元测试的方式执行验证。本地测试创建函数 App 并调用实例方法与 HTTP 测试不同Timer 触发器的测试流程是通过createFunctionApp创建函数 App再通过getServerlessInstance获取整个类的实例从而直接调用到被装饰的方法进行断言。同时可以使用createTimerEvent方法快速构造平台传入的事件结构。完整测试示例如下import { createFunctionApp, close } from midwayjs/mock; import { Framework, Application } from midwayjs/serverless-app; import { HelloAliyunService } from ../src/function/hello_aliyun; import { createTimerEvent, createInitializeContext } from midwayjs/serverless-fc-trigger; import { join } from path; describe(test/hello_aliyun.test.ts, () { let app: Application; let instance: HelloAliyunService; beforeAll(async () { // create app app await createFunctionAppFramework(join(__dirname, ../), { initContext: createInitializeContext(), }); instance await app.getServerlessInstanceHelloAliyunService(HelloAliyunService); }); afterAll(async () { await close(app); }); it(should get result from timer trigger, async () { expect(await instance.handleTimerEvent(createTimerEvent())).toEqual(hello world); }); });测试要点createFunctionAppFramework(join(__dirname, ../), { initContext: createInitializeContext() })以项目根目录为基准创建函数 AppcreateInitializeContext用于提供模拟的平台初始化上下文app.getServerlessInstanceHelloAliyunService(HelloAliyunService)获取类实例等价于在真实运行环境中由容器装配并注入ctx后的实例createTimerEvent()一键生成上文所述的{ triggerTime, triggerName, payload }结构直接作为方法入参由于调用的是真实的方法逻辑测试结果可完整覆盖定时业务代码的执行路径包括this.ctx.logger输出。这样的测试既验证了触发方法的返回值也验证了类在被平台实例化后的完整装配链路与 HTTP 触发的本地测试方式通过请求入口调用形成互补。关闭触发器避免额外扣费函数计算平台通常按调用次数与运行时长计费定时触发器一旦部署就会周期性自动执行哪怕业务代码尚未完善也会持续产生调用。因此文档中特别提醒温馨提醒测试函数后请及时关闭触发器自动执行避免超额扣费。如果不再使用某个定时任务请务必前往平台控制台关闭触发器或者直接删除该触发器乃至整个函数避免无谓的持续调用与扣费。源码与测试佐证如果你希望进一步深入理解 Timer 触发器的实现与测试方式可以查看以下仓库文件packages/core/src/interface.ts#L251-L256TimerTriggerOptions类型定义type / value / payload / enablepackages/core/src/interface.ts#L295-L308ServerlessTriggerType枚举TIMER timerpackages/core/src/decorator/faas/serverlessTrigger.ts#L61-L85ServerlessTrigger装饰器的元数据写入实现packages/core/test/fixtures/app-with-serverless-trigger/src/function/hello_aliyun.ts包含 cron / every 多 Timer 触发器、自定义name的完整示例packages/core/test/service/slsFunctionService.test.ts针对上述夹具的 Serverless 函数服务测试。小结Timer 触发器是 Midway 2.0 Serverless 体系中最常用的「定时执行」方案用ServerlessTrigger(ServerlessTriggerType.TIMER, { type, value })一行声明cron负责精确时刻、every负责周期轮询配合FC.TimerEvent事件结构与createTimerEvent本地测试工具即可在开发、测试、部署全链路完成定时任务的交付。唯一需要牢记的实践要点有两个一是UTC 时区换算二是测试完成后及时关闭触发器避免超额扣费。赞分享后端微服务云原生【免费下载链接】midway A Node.js Serverless Framework for front-end/full-stack developers. Build the application for next decade. Works on AWS, Alibaba Cloud, Tencent Cloud and traditional VM/Container. Super easy integrate with React and Vue. 项目地址https://gitcode.com/gh_mirrors/mi/midway点击查看免费下载相关推荐Midway定时任务终极指南Cron表达式与任务调度实战Midway定时任务终极指南Cron表达式与任务调度实战 在现代Web应用开发中定时任务是不可或缺的重要功能。Midway作为优秀的Node.js Serv后端微服务云原生Laf 云函数定时触发器Cron Trigger实现指南Laf 云函数定时触发器Cron Trigger实现指南 本文基于 Laf 官方文档「定时任务」章节结合服务端源码完整讲解 Laf 云函数定时触发器的使后端Serverless前端云原生Midway 任务调度实战分布式定时任务、延迟任务与本地 Cronmidwayjs/taskMidway 任务调度实战分布式定时任务、延迟任务与本地 Cronmidwayjs/task 导读 本文聚焦 Midway 框架中基于 midwayj后端微服务云原生上一篇MKS Monster8 8轴主板完整配置实战30分钟搞定接线、固件刷写与调优下一篇MPC-BE全屏控制栏不显示5步找回消失的底部工具条创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进