ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

在 Redwood 中使用 Exec 命令与 Faktory 构建后台 Worker

在 Redwood 中使用 Exec 命令与 Faktory 构建后台 Worker 后端前端Web框架开发工具【免费下载链接】redwoodRedwoodGraphQL项目地址https://gitcode.com/gh_mirrors/re/redwood点击查看免费下载本篇技术指南以 Redwoodv8.0的execCLI 命令为主线演示如何借助 Faktory——一个语言无关、持久化的后台任务服务器——在 Redwood 应用中搭建独立的后台 Worker将耗时操作如发送欢迎邮件从请求/响应周期中剥离出来交给独立进程异步执行。读完本文你将掌握「生成可执行脚本 → 注册后台任务 → 在 Service 中入队任务 → 运行 Worker」的完整落地路径并理解exec命令在 Redwood CLI 内部的真实执行机制。为什么需要后台 Worker在典型的注册流程中用户提交注册表单后服务端不仅要写数据库、创建认证记录往往还要调用第三方邮件服务发送欢迎邮件。这些操作串行执行时用户等待的时间会显著拉长——发送邮件甚至可能比请求中所有其他工作的总和还要久。更好的做法是把这些不影响用户当前任务的操作移出请求周期打包成独立的后台任务Background Job交给另一个进程去执行。用户请求立刻返回邮件随后异步送达。在 Redwood 生态中实现这种异步化有两条路线内置的后台任务系统Background Jobs通过yarn rw setup jobs配置使用 PrismaAdapter 将任务存储在数据库中详见 Background Jobs 官方指南本文的方案利用exec命令把任意 Node.js 脚本跑成常驻 Worker 进程配合 Faktory 这类独立的任务队列服务器。本文聚焦第二种方案它不依赖数据库存储任务队列的调度、持久化与重试全部交给 Faktory 完成Redwood 应用只需负责注册任务和执行任务。整体架构与工作流程Faktory 是一个语言无关的持久化后台任务服务器可以独立部署官方支持 Docker 方式运行应用侧通过 Node.js 客户端库faktory-worker与其通信。整个方案包含三个角色Redwood 应用负责定义任务的实现api/src/lib/tasks.js并在业务 Service 中把任务推送到 Faktory 服务器Faktory 服务器作为任务队列的中转站接收、存储并分发任务Worker 进程由yarn rw exec faktoryWorker启动的常驻脚本从 Faktory 拉取任务并执行。从源码结构看Redwood 的exec命令命令定义位于 CLI 包中它的设计初衷之一正是后台 Worker这类长驻脚本——CLI 文档明确列出了三类典型用法一次性脚本如同步 Stripe 商品到数据库、可卸载长任务的后台 Worker、开发期的自定义 seed 脚本。第一步生成 Worker 脚本在 Redwood 项目根目录执行yarn rw g script faktoryWorkerg是generate的别名。该命令由 script 生成器实现会在项目的scripts/目录下生成faktoryWorker.jsTypeScript 项目则生成.ts文件并附带一份scripts/tsconfig.json。生成的脚本骨架脚本模板源码大致如下// Append api/* to import from api and web/* to import from web // To access your database uncomment the line below // import { db } from api/src/lib/db interface Args { _: string[] [key: string]: unknown } export default async ({ args }: Args) { // Your script here... console.log(:: Executing script with args ::) console.log(args) }几个关键点脚本默认导出一个异步函数接收{ args }参数其中args包含执行时传入的全部命令行参数脚本位于scripts/目录但可以直接importAPI 侧api/src的模块——这正是exec命令赋予脚本的能力见下文源码剖析yarn rw g script也支持--typescript/--ts选项强制生成 TS 版本默认会根据项目类型自动判断。第二步编写 Worker 并注册任务接下来在生成的scripts/faktoryWorker.js中注册名为postSignupTask的任务并启动 Workerimport { postSignupTask } from $api/src/lib/tasks import { logger } from $api/src/lib/logger import faktory from faktory-worker faktory.register(postSignupTask, async (taskArgs) { logger.info(running postSignupTask in background worker) await postSignupTask(taskArgs) }) export default async ({ _args }) { const worker await faktory .work({ url: process.env.FAKTORY_URL, }) .catch((error) { logger.error(worker failed to start: ${error}) process.exit(1) }) worker.on(fail, ({ _job, error }) { logger.error(worker failed to start: ${error}) }) }这段代码做了三件事导入依赖通过$api/src/lib/tasks别名导入任务实现通过$api/src/lib/logger导入 Redwood 的 logger便于任务日志与应用的日志体系统一注册任务faktory.register(postSignupTask, ...)告诉 Worker当队列中出现名为postSignupTask的任务时执行回调函数并透传taskArgs参数启动 Workerfaktory.work({ url })建立与 Faktory 服务器的连接并开始消费任务启动失败时记录错误并以非零码退出监听fail事件以记录单个任务执行失败的情况。注意原文档中该文件第一行写作const { postSignupTask } from $api/src/lib/tasks这是笔误——正确的 ESM 语法应为import { postSignupTask } from $api/src/lib/tasks与后续的import语句保持一致。上面代码已按正确语法给出。此时直接运行 Worker 还无法工作因为postSignupTask尚未在api/src/lib/tasks.js中实现且FAKTORY_URL环境变量还未设置。第三步配置 FAKTORY_URL在项目根目录的.env文件中设置环境变量指向你的 Faktory 服务器地址FAKTORY_URLtcp://127.0.0.1:7419Faktory 服务器默认监听7419端口tcp协议。如果你的 Faktory 部署在远程主机或自定义端口把地址替换为实际值即可。Worker 启动时会从process.env.FAKTORY_URL读取该配置对应上文代码中的url: process.env.FAKTORY_URL。第四步实现后台任务在api/src/lib/tasks.js中实现postSignupTask。这类任务通常涉及与外部服务的交互——例如发送邮件——这正是典型的不该阻塞请求周期的工作export const postSignupTask async ({ userId, emailPayload }) { // Send a welcome email to new user. // Youll have to have an integration with an email service for this to work. await sendEmailWithTemplate({ ...emailPayload, TemplateModel: { ...emailPayload.TemplateModel, }, }) }要点任务函数从taskArgs解构出业务所需的数据这里是userId与emailPayload保持任务的自包含性——任务自身携带执行所需的全部信息不依赖调用方的上下文sendEmailWithTemplate是对邮件服务商的封装需要你预先接入相应的邮件服务如 发送邮件 how-to 中的方案把任务实现放在api/src/lib/而非scripts/下的原因任务逻辑属于应用的一部分可以被 Service、其他脚本复用同时保持scripts/目录只存放入口型的可执行脚本。第五步在 Service 中入队任务任务创建好后需要在合适的时机把任务推送到 Faktory 服务器。对postSignupTask而言最自然的时机是用户完成注册之后。下面是一个典型的 Service 示例——它通常通过 GraphQL Mutation 被调用const faktory require(faktory-worker) export const signUp async ({ input }) { // Perform all the signup operations, such as creating an entry in the DB and auth provider // ... // Then, send our task to the Faktory server const client await faktory.connect() await client.job(postSignupTask, { ...taskArgs }).push() await client.close() }流程说明faktory.connect()建立与 Faktory 服务器的客户端连接同样读取FAKTORY_URL等配置client.job(postSignupTask, { ...taskArgs })声明要推送的任务名与负载数据.push()把任务写入 Faktory 队列随即返回——用户的请求到这里就结束了邮件发送被完全移出请求周期client.close()释放连接。值得注意的是Service 侧只负责入队并不关心任务何时、由谁执行——这是后台任务系统解耦的关键。只要 Worker 进程在运行它就会从 Faktory 拉取postSignupTask并执行我们在第一步注册的回调进而调用api/src/lib/tasks.js中的实现。第六步运行 Worker 并验证一切就绪后用 Docker 启动 Faktory 服务器运行 Workeryarn rw exec faktoryWorker如果 Faktory 服务器运行正常且FAKTORY_URL配置无误你会看到服务器开始接收任务、Worker 进程消费并处理任务。触发一次signUpMutation 后postSignupTask就会被异步执行对应日志中会出现running postSignupTask in background worker的输出。exec 命令源码剖析exec之所以能让scripts/下的脚本直接使用$api、$web别名并访问项目内模块是因为它在底层做了完整的 Babel 与模块解析配置。这一机制可以从 execHandler.js 的实现中确认Babel 钩子注册调用registerApiSideBabelHook并注入babel-plugin-module-resolver将$api映射到api目录、$web映射到web目录、src映射到对应侧的src目录见 exec.js 中的配置函数。这正是脚本中import ... from $api/src/lib/logger能够生效的原因脚本解析resolveScriptPath会在scripts/目录下按.js、.jsx、.ts、.tsx四种扩展名查找脚本若同名脚本存在多种扩展名会要求显式指定扩展名此时yarn rw exec --list也会在列表中带扩展名展示执行方式runScriptFunction源码直接require脚本文件并调用其default导出函数传入{ args: scriptArgs }脚本运行结束后会自动调用 Prisma 的db.$disconnect()优雅关闭数据库连接该调用被 try/catch 包裹无数据库时静默跳过参数透传yargs 解析出的位置参数与命名参数如--firstParam hello会进入脚本的args对象脚本模板默认打印出来方便调试Prisma 客户端exec默认会先执行Generating Prisma client步骤可通过--no-prisma跳过确保脚本可安全使用db。exec命令本身还支持--list/-l列出scripts/下所有可用脚本与--silent/-s只输出脚本自身输出选项。这些行为在 exec.test.ts 测试用例中有完整覆盖包括嵌套目录脚本的展示、扩展名歧义时的处理以及参数透传的断言可作为理解该命令行为的参考。注意事项与最佳实践1. Worker 与 Server 的职责边界Worker 脚本scripts/faktoryWorker.js只做拉取任务 分发真正的业务逻辑放在api/src/lib/tasks.js。这样任务实现可以被 Service、测试和其他脚本复用避免在 Worker 中堆积业务代码。2. 失败处理与重试Faktory 本身对任务失败有内置的重试与死信队列机制Worker 侧通过worker.on(fail, ...)记录任务级失败启动失败则process.exit(1)让进程管理工具如 systemd、PM2感知并重启。生产环境建议将 Worker 作为常驻服务管理并为其配置独立的日志输出。3. 环境变量管理FAKTORY_URL存放在.envRedwood 会自动加载。注意区分开发与生产环境的服务器地址避免本地 Worker 误连生产队列。4. 与内置 Background Jobs 的取舍如果不想引入独立的 Faktory 服务器可以评估 Redwood 内置的 Background Jobs 系统它通过yarn rw setup jobs与yarn rw g job提供开箱即用的调度立即/延时/定时、队列分组与优先级排序任务直接存储在数据库中。本文的 Faktory 方案更适合已有 Faktory 基础设施、或希望与多语言服务共享同一任务队列的场景。5. 任务的自包含性入队时传给任务的数据应足够完整如postSignupTask的userId与emailPayload让任务在独立进程中无需访问调用方上下文即可执行不要传递不可序列化的对象或过大的数据负载。至此一个基于exec与 Faktory 的完整后台 Worker 方案已经落地注册事件触发 Service 入队Worker 常驻消费耗时操作彻底移出请求周期。你可以在此基础上扩展更多任务类型、接入任务监控与告警让后台执行体系逐步完善。赞分享后端前端Web框架开发工具【免费下载链接】redwoodRedwoodGraphQL项目地址https://gitcode.com/gh_mirrors/re/redwood点击查看免费下载相关推荐在 Redwood 中使用 exec 命令与 Faktory 构建后台任务 Worker在 Redwood 中使用 exec 命令与 Faktory 构建后台任务 Worker 导读后台任务Background Worker是 Web 应用中后端前端Web框架开发工具Redwood 后台任务实战使用 exec 命令与 Faktory 构建后台 WorkerRedwood 后台任务实战使用 exec 命令与 Faktory 构建后台 Worker 导读 本文基于 Redwood 官方 How To 文档 doc后端前端Web框架开发工具使用 Exec 与 Faktory 在 Redwood 中构建后台任务 Worker使用 Exec 与 Faktory 在 Redwood 中构建后台任务 Worker 导读 本文基于 Redwood 官方 How To 文档完整演示如何利用后端前端Web框架开发工具上一篇【亲测免费】 开源项目推荐Emulsion下一篇【亲测免费】 Deequ基于Apache Spark的数据质量检测工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表