使用 @midwayjs/one-shot 在 Midway 中执行一次性脚本任务

发布时间:2026/10/9 12:45:48
使用 @midwayjs/one-shot 在 Midway 中执行一次性脚本任务
后端微服务云原生【免费下载链接】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 官方扩展midwayjs/one-shot展开介绍如何在一个普通 Node.js 项目中以 IoC依赖注入方式编排一次性脚本one-shot task包括组件安装、入口配置、生命周期内执行、基于 request-scope 的runScript运行方式以及内置日志器的定制。读完本文你将掌握一个不启动 HTTP/Serverless 服务、只跑一次业务逻辑、却能完整复用 Midway 依赖注入与中间件链路的轻量框架用法。什么是 midwayjs/one-shotmidwayjs/one-shot是一个只提供 Framework的一次性脚本框架。它不包含独立的 HTTP 服务、不面向 Serverless 平台也不参与应用集成场景定位非常纯粹在一个已有项目中借助 Midway 的 IoC 容器执行一次性的任务。官方文档给出了该组件的能力矩阵描述是否支持可用于标准 Web 应用❌可用于 Serverless 场景❌可用于集成场景integrated❌包含独立的核心standalone core✅包含独立的日志器standalone logger✅换句话说它把 Midway 的核心 日志能力以独立框架的形式拆出来供批处理、数据同步、定时补偿等场景复用而不会引入多余的网络层。从仓库结构看该组件位于 packages/one-shot当前版本为4.2.5依赖仅midwayjs/core见 package.json运行时要求 Node.js 20。安装组件在已有项目中安装 one-shot 组件依赖$ npm i midwayjs/one-shot4 --save也可以在package.json中直接声明依赖后重新安装{ dependencies: { midwayjs/one-shot: ^4.0.0 } }由于midwayjs/one-shot在src/index.ts中通过export { MidwayOneShotFramework as Framework }与export { OneShotConfiguration as Configuration }对外暴露框架与配置入口见 src/index.ts安装后只需在配置类中导入即可使用。启用组件在入口配置src/configuration.ts中导入并注册组件// src/configuration.ts import { Configuration } from midwayjs/core; import * as oneShot from midwayjs/one-shot; Configuration({ imports: [oneShot], }) export class MainConfiguration {}组件内部通过Configuration({ namespace: oneShot, importConfigs: [...] })注册了名为oneShot的命名空间并顺带声明了默认日志配置见 src/configuration.ts因此无需任何额外初始化动作即可工作。在生命周期中执行一次性逻辑midwayjs/one-shot不需要额外的 Runner 概念官方推荐的执行时机是应用生命周期钩子onServerReady。此时应用已完成装配、所有 IoC 依赖均可注入可以直接调用业务服务// src/configuration.ts import { Configuration, Inject } from midwayjs/core; import * as oneShot from midwayjs/one-shot; import { ScriptService } from ./service/script; Configuration({ imports: [oneShot], }) export class MainConfiguration { Inject() scriptService: ScriptService; async onServerReady() { await this.scriptService.runOnce(); } }这里ScriptService是项目内普通Provide()业务类依赖注入完全走 Midway 容器。因为 one-shot 框架的run()方法是按需执行的源码中为空的public async run(): Promisevoid见 src/framework.ts所以整体启动流程很短适合进程启动 → 跑一次 → 退出的命令行任务形态。当脚本需要请求级作用域request scope时如果你的脚本依赖请求级request-scope服务生命周期钩子里直接注入的方式就不够用了——生命周期钩子运行在应用级作用域无法天然获得请求级上下文。此时应使用框架提供的runScriptAPI 并搭配一个固定的 Runner 类框架会为这一次执行创建一个独立的 context并运行完整的中间件middleware与过滤器filter链路。定义 Runner 类Runner 需要实现OneShotRunnerT, R接口其中泛型T为入参 payload 类型、R为返回值类型// src/script/syncUser.ts import { Provide } from midwayjs/core; import { OneShotRunner, Context } from midwayjs/one-shot; Provide() export class SyncUserScript implements OneShotRunner{ id: number }, void { async run(payload?: { id: number }, ctx?: Context) { // use payload / ctx void payload; void ctx; } }接口定义位于 src/interface.tsexport interface OneShotRunnerT unknown, R unknown { run(payload?: T, ctx?: IMidwayOneShotContext): R | PromiseR; }其中上下文IMidwayOneShotContext继承自 Midway 通用上下文并额外带有一个payload字段见 src/interface.ts因此你既可以通过run的第二个参数拿到ctx也可以在 Runner 内部用Inject() ctx: Context注入上下文并读取ctx.payload。调用 runScript在配置类生命周期中通过注入的Framework调用// src/configuration.ts import { Configuration, Inject } from midwayjs/core; import * as oneShot from midwayjs/one-shot; import { Framework } from midwayjs/one-shot; import { SyncUserScript } from ./script/syncUser; Configuration({ imports: [oneShot], }) export class MainConfiguration { Inject() framework: Framework; async onServerReady() { await this.framework.runScript(SyncUserScript, { id: 42 }); } }runScript的完整签名支持三个参数见 src/framework.tspublic async runScriptT unknown, R unknown( Runner: new (...args: unknown[]) OneShotRunnerT, R, payload?: T, ctxData: PartialIMidwayOneShotContext {} ): PromiseR底层执行链路源码解读runScript的内部实现src/framework.ts清晰地展现了它的设计意图创建匿名上下文调用this.app.createAnonymousContext({ ...ctxData, payload })生成一次执行专属的上下文payload被直接挂到上下文中。createAnonymousContext是BaseFramework提供的能力见 packages/core/src/baseFramework.ts它会为上下文补齐startTime、上下文日志器、requestContext请求级容器以及traceId等属性——这正是 one-shot 能够运行请求级依赖和中间件的根本原因。链路追踪通过MidwayTraceService.runWithEntrySpan创建名为oneshot ${Runner.name}的入口 span并写入midway.protocol: one-shot、midway.oneshot.runner等属性。tracing配置项可通过oneShot.tracing.enable关闭并支持自定义extractor/meta回调来提取链路载体。执行中间件链用applyMiddleware包裹真实业务逻辑然后在匿名上下文上运行整条中间件链。真正执行业务时先从ctx.requestContext请求级容器中getAsync(Runner)解析出 Runner 实例——这一步保证了 Runner 可以注入 request-scope 服务——随后校验实例上存在run()方法不存在则抛出MidwayCommonError(One-shot runner must implement run().)最后调用instance.run(payload, ctx)并把结果作为R返回。仓库自带的测试 test/index.test.ts 验证了这套链路SampleScript通过Inject() ctx: Context注入上下文runScript(SampleScript, { id: 42 })返回42:42payload 与 ctx.payload 一致第二个用例还通过监听MidwayTraceService.runWithEntrySpan断言每次runScript都会创建入口 span。日志内置 oneShotLogger组件默认注册一个名为oneShotLogger的日志器写入文件midway-one-shot.log。默认配置在组件的importConfigs中声明见 src/configuration.ts。你可以在脚本服务中通过Logger(oneShotLogger)注入并使用import { Logger, ILogger } from midwayjs/core; export class ScriptService { Logger(oneShotLogger) logger: ILogger; async runOnce() { this.logger.info(run one-shot task); } }如果想自定义日志文件名或日志级别可以在应用配置中覆盖midwayLogger.clients.oneShotLogger// src/config/config.default.ts export default { midwayLogger: { clients: { oneShotLogger: { fileLogName: my-one-shot.log, level: info, }, }, }, };由于默认配置与用户配置都会合并进midwayLogger.clients因此只需覆写需要变更的字段如fileLogName、level即可其余日志器行为仍沿用 Midway 统一的日志配置体系。小结与适用场景midwayjs/one-shot适合以下场景需要跑一次的数据迁移、数据同步、批量补偿任务希望复用项目既有 IoC 服务与配置又不想引入完整 Web 或 Serverless 框架脚本逻辑依赖 request-scope 服务或需要经过中间件/过滤器链路时使用runScript Runner 类。需要注意的前提它不适用于标准 Web 应用、Serverless 或集成模式见上文能力矩阵核心定位就是跑一次即退出的 IoC 化脚本。实际使用中只需安装组件、在configuration.ts注册并在onServerReady中按需触发即可源码层面的运行链路可继续参考 packages/one-shot/src/framework.ts 与 packages/one-shot/test/index.test.ts。赞分享后端微服务云原生【免费下载链接】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 一次性脚本执行指南使用 midwayjs/one-shot 在 IoC 容器中触发单次任务Midway 一次性脚本执行指南使用 midwayjs/one shot 在 IoC 容器中触发单次任务 midwayjs/one shot 是 Midw后端微服务云原生Midway 4.0 Beta.10 新组件实战midwayjs/one-shot 一次性脚本执行 与 midwayjs/commander 命令行组件全解析Midway 4.0 Beta.10 新组件实战midwayjs/one shot 一次性脚本执行 与 midwayjs/commander 命令行组件全后端微服务云原生Dokku 一次性任务One-off Tasks实战指南用 run 命令在应用容器中执行临时命令Dokku 一次性任务One off Tasks实战指南用 run 命令在应用容器中执行临时命令 本文围绕 Dokku 平台的一次性任务one off云原生DevOps后端上一篇SciPy 文档体系中的 Sphinx Autosummary 属性模板attribute.rst 逐行解析与生成链路下一篇Pandoc 脚注内引文Citation in Note机制深度解析以 Chicago Full Note 风格回归测试 7394 为例创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考