戰(zhàn):基于 Exec 命令與 Faktory 構(gòu)建持久化后臺(tái)任務(wù) Worker)
后端前端Web框架開發(fā)工具【免費(fèi)下載鏈接】redwoodRedwoodGraphQL項(xiàng)目地址https://gitcode.com/gh_mirrors/re/redwood點(diǎn)擊查看免費(fèi)下載在本篇技術(shù)指南中我們將圍繞 Redwood 的execCLI 命令完整演示如何借助 Faktory 這一語言無關(guān)的持久化后臺(tái)任務(wù)服務(wù)器構(gòu)建一個(gè)可以脫離請(qǐng)求/響應(yīng)周期運(yùn)行的異步 Worker從生成腳本、注冊(cè)任務(wù)、配置環(huán)境變量到在 Service 中投遞任務(wù)、最終啟動(dòng) Worker 消費(fèi)任務(wù)全流程可復(fù)制可運(yùn)行。讀完本文你將掌握在 Redwood 應(yīng)用中落地注冊(cè)后發(fā)歡迎郵件這類后臺(tái)任務(wù)的完整實(shí)現(xiàn)方案并理解yarn rw exec的底層執(zhí)行機(jī)制。為什么需要后臺(tái)任務(wù)與 Faktory在典型的 Web 應(yīng)用中一些操作如發(fā)送歡迎郵件、同步第三方數(shù)據(jù)、清理過期數(shù)據(jù)并不適合阻塞在 GraphQL Mutation 的請(qǐng)求/響應(yīng)周期里。它們耗時(shí)長、依賴外部服務(wù)一旦失敗還會(huì)拖垮用戶請(qǐng)求。這類工作最適合放到后臺(tái)異步執(zhí)行。Faktory 是一個(gè)語言無關(guān)language-agnostic、持久化的后臺(tái)任務(wù)服務(wù)器它本身與語言無關(guān)任何語言的客戶端都可以與它通信任務(wù)數(shù)據(jù)被持久化保存即使 Worker 進(jìn)程崩潰任務(wù)也不會(huì)丟失。在 Redwood 應(yīng)用中我們通過faktory-worker這個(gè) Node 客戶端庫與 Faktory 服務(wù)器通信——Worker 端用它注冊(cè)并消費(fèi)任務(wù)應(yīng)用端Service用它把任務(wù)投遞到服務(wù)器。整體架構(gòu)分為三部分Faktory 服務(wù)器負(fù)責(zé)接收、排隊(duì)并持久化任務(wù)可用 Docker 一鍵啟動(dòng)Redwood Worker 腳本由yarn rw g script生成的 Node 腳本注冊(cè)任務(wù)處理器長駐運(yùn)行等待消費(fèi)任務(wù)Redwood 應(yīng)用在 Service如注冊(cè)邏輯中把任務(wù)推送到 Faktory 服務(wù)器。第一步生成 Worker 腳本Redwood 的generate script命令會(huì)在./scripts/name下生成一個(gè)可獨(dú)立執(zhí)行的 Node.js 腳本文件。打開終端執(zhí)行yarn rw g script faktoryWorker生成器會(huì)輸出類似如下的提示告訴我們?nèi)绾握{(diào)用這個(gè)腳本? Generating script file... ? Successfully wrote file ./scripts/faktoryWorker.ts ? Next steps... After modifying your script, you can invoke it like: yarn rw exec faktoryWorker yarn rw exec faktoryWorker --param1 true從生成器模板見 script.ts.template可以看出腳本默認(rèn)結(jié)構(gòu)如下腳本默認(rèn)導(dǎo)出函數(shù)接收{(diào) args }其中args._是位置參數(shù)數(shù)組其余為具名參數(shù)// 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) }關(guān)鍵點(diǎn)在于腳本中可以使用api/src/...前綴導(dǎo)入 API 側(cè)的服務(wù)與庫如$api/src/lib/logger、api/src/lib/db這正是 Worker 能復(fù)用 Redwood 業(yè)務(wù)代碼的基礎(chǔ)。如果你的項(xiàng)目啟用了 TypeScript生成器會(huì)自動(dòng)生成.ts文件參見 generate script 文檔。第二步注冊(cè)任務(wù)處理器編輯scripts/faktoryWorker.js用faktory-worker注冊(cè)一個(gè)名為postSignupTask的任務(wù)并在默認(rèn)導(dǎo)出函數(shù)中啟動(dòng) Worker 長駐進(jìn)程const { 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}) }) }逐段解讀這段代碼faktory.register(postSignupTask, ...)向 Worker 注冊(cè)任務(wù)名稱及其處理函數(shù)。Faktory 服務(wù)器推送過來名為postSignupTask的任務(wù)時(shí)會(huì)執(zhí)行這里注冊(cè)的異步回調(diào)faktory.work({ url: process.env.FAKTORY_URL })讓 Worker 連接 Faktory 服務(wù)器并開始消費(fèi)任務(wù)連接地址來自環(huán)境變量FAKTORY_URL連接失敗時(shí)記錄錯(cuò)誤并process.exit(1)退出worker.on(fail, ...)監(jiān)聽單個(gè)任務(wù)執(zhí)行失敗事件便于集中記錄失敗原因示例代碼中的日志文案與啟動(dòng)失敗相同實(shí)際項(xiàng)目中可改為任務(wù)執(zhí)行失敗等更貼切的描述。目前這段代碼還不能運(yùn)行因?yàn)閜ostSignupTask還沒有在api/src/lib/tasks.js中定義FAKTORY_URL也還沒有配置。第三步配置 FAKTORY_URL在項(xiàng)目根目錄的.env文件中設(shè)置FAKTORY_URL指向你的 Faktory 服務(wù)器地址FAKTORY_URLtcp://localhost:7419Faktory 默認(rèn)監(jiān)聽 7419 端口Web UI 默認(rèn)在 7420。如果使用 Docker 啟動(dòng)服務(wù)器請(qǐng)確認(rèn)端口映射與本配置一致。只有FAKTORY_URL配置正確、服務(wù)器在線Worker 才能啟動(dòng)并消費(fèi)任務(wù)。第四步實(shí)現(xiàn)后臺(tái)任務(wù)在api/src/lib/tasks.js中實(shí)現(xiàn)postSignupTask。這個(gè)函數(shù)負(fù)責(zé)真正執(zhí)行后臺(tái)工作例如調(diào)用外部郵件服務(wù)發(fā)送歡迎郵件——這類耗時(shí)、依賴外部網(wǎng)絡(luò)的操作正適合放到后臺(tái)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, }, }) }這里sendEmailWithTemplate是對(duì)郵件服務(wù)商的封裝實(shí)際項(xiàng)目需自行實(shí)現(xiàn)或接入第三方服務(wù)。函數(shù)接收{(diào) userId, emailPayload }作為任務(wù)參數(shù)這兩個(gè)字段正是后續(xù)從 Service 投遞任務(wù)時(shí)傳入的數(shù)據(jù)。由于tasks.js位于api/src/libWorker 腳本通過$api/src/lib/tasks導(dǎo)入即可復(fù)用同一份實(shí)現(xiàn)業(yè)務(wù)邏輯只寫一次。第五步在 Service 中投遞任務(wù)任務(wù)定義好后需要在合適的業(yè)務(wù)節(jié)點(diǎn)把它投遞出去。對(duì)postSignupTask來說最合理的位置是用戶完成注冊(cè)之后——通常是會(huì)被 GraphQL Mutation 調(diào)用的 Service。下面是一個(gè)src/services/auth/auth.js的示例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() }這段代碼的關(guān)鍵動(dòng)作faktory.connect()建立到 Faktory 服務(wù)器的客戶端連接地址同樣取自FAKTORY_URLclient.job(postSignupTask, { ...taskArgs }).push()將postSignupTask任務(wù)連同參數(shù)推送到服務(wù)器。Faktory 會(huì)持久化該任務(wù)并等待 Worker 消費(fèi)client.close()投遞完成后關(guān)閉連接釋放資源。注意這里的任務(wù)參數(shù)taskArgs會(huì)作為taskArgs傳給 Worker 中的處理函數(shù)因此在postSignupTask實(shí)現(xiàn)中解構(gòu)的{ userId, emailPayload }必須與這里投遞的數(shù)據(jù)結(jié)構(gòu)保持一致。至此一條完整的后臺(tái)任務(wù)鏈路已經(jīng)打通用戶注冊(cè) → Service 投遞任務(wù)到 Faktory → Worker 消費(fèi)任務(wù) → 執(zhí)行postSignupTask發(fā)送歡迎郵件。啟動(dòng)服務(wù)器并運(yùn)行 Worker先用 Docker 啟動(dòng) Faktory 服務(wù)器需要提前安裝 Docker 并拉取 Faktory 鏡像映射好 7419 端口然后在項(xiàng)目根目錄運(yùn)行 Workeryarn rw exec faktoryWorker如果 Faktory 服務(wù)器在線、FAKTORY_URL配置正確你會(huì)看到服務(wù)器拾取 Service 投遞的任務(wù)Worker 進(jìn)程隨即消費(fèi)并處理這些任務(wù)。exec命令本身提供了一些實(shí)用選項(xiàng)定義見 exec.js選項(xiàng)別名默認(rèn)值說明name位置參數(shù)——要運(yùn)行的腳本文件名擴(kuò)展名可省略--prisma—true運(yùn)行腳本前是否生成 Prisma Client--list-lfalse僅列出所有可用腳本不執(zhí)行--silent-sfalse靜默 Redwood 自身的輸出只保留腳本輸出例如查看當(dāng)前項(xiàng)目有哪些腳本可以運(yùn)行yarn rw exec --listexec 底層是如何工作的理解exec的執(zhí)行機(jī)制有助于排查腳本運(yùn)行問題。核心實(shí)現(xiàn)在 execHandler.js其處理流程大致如下定位腳本通過findScripts掃描scripts/目錄下的所有腳本文件并按文件名去擴(kuò)展名分組未指定腳本名或使用--list時(shí)會(huì)列出所有可用腳本解析參數(shù)CLI 通過 yargs 解析命令exec [name]會(huì)把腳本名放入name變量其余位置參數(shù)進(jìn)入args._并剔除exec與$0具名參數(shù)如--firstParam hello則作為屬性傳入最終組合成傳給腳本的args對(duì)象注冊(cè) Babel 鉤子腳本中$api/src/...、api/src/...這類別名導(dǎo)入之所以可用是因?yàn)閳?zhí)行器注冊(cè)了 API 側(cè)的 Babel 轉(zhuǎn)換鉤子registerApiSideBabelHook讓腳本在運(yùn)行時(shí)能解析 Redwood 的路徑別名與 ESM 語法生成 Prisma Client默認(rèn)在運(yùn)行前生成 Prisma Client可通過--prisma false關(guān)閉保證腳本中使用db時(shí)數(shù)據(jù)庫訪問可用執(zhí)行腳本調(diào)用腳本默認(rèn)導(dǎo)出的異步函數(shù)傳入解析好的args。官方文檔對(duì)exec的定位是執(zhí)行yarn redwood generate script name生成的腳本用于一次性操作、長任務(wù)或工具腳本見 exec 章節(jié)典型場景包括將 Stripe 產(chǎn)品同步到數(shù)據(jù)庫的一次性腳本、可離線處理長任務(wù)的后臺(tái) Worker、開發(fā)期的自定義種子數(shù)據(jù)腳本等。更進(jìn)一步的參考如果你希望深入了解generate script的參數(shù)選項(xiàng)如--typescript、--rollback參見 CLI 命令參考運(yùn)行exec時(shí)如果想觀察腳本收到的參數(shù)可在腳本內(nèi)console.log(args)執(zhí)行yarn rw exec faktoryWorker foo --firstParam hello即可看到{ _: [foo], firstParam: hello }形式的輸出若項(xiàng)目需要更框架化、內(nèi)建的后臺(tái)任務(wù)能力與 Prisma 深度集成、自帶重試與隊(duì)列管理可進(jìn)一步閱讀 background-jobs.md將其與本文的Exec Faktory輕量方案對(duì)比選型。小結(jié)本文完整演示了在 Redwood 中使用execCLI 命令與 Faktory 搭建后臺(tái) Worker 的五個(gè)步驟生成腳本、注冊(cè)任務(wù)、配置FAKTORY_URL、實(shí)現(xiàn)任務(wù)函數(shù)、在 Service 中投遞任務(wù)并最終通過yarn rw exec faktoryWorker啟動(dòng)消費(fèi)。這套方案把耗時(shí)操作從請(qǐng)求/響應(yīng)周期中剝離同時(shí)借助 Faktory 的持久化能力保證任務(wù)不丟失是 Redwood 應(yīng)用處理發(fā)送郵件、同步第三方數(shù)據(jù)等異步工作的實(shí)用選擇。贊分享后端前端Web框架開發(fā)工具【免費(fèi)下載鏈接】redwoodRedwoodGraphQL項(xiàng)目地址https://gitcode.com/gh_mirrors/re/redwood點(diǎn)擊查看免費(fèi)下載相關(guān)推薦Redwood 實(shí)戰(zhàn)基于 Exec 命令與 Faktory 構(gòu)建后臺(tái)任務(wù) WorkerRedwood 實(shí)戰(zhàn)基于 Exec 命令與 Faktory 構(gòu)建后臺(tái)任務(wù) Worker 本文是一份面向 Redwood 應(yīng)用開發(fā)者的實(shí)戰(zhàn)指南核心主題是借助后端前端Web框架開發(fā)工具Redwood 后臺(tái)任務(wù)實(shí)戰(zhàn)使用 exec 命令與 Faktory 構(gòu)建后臺(tái) WorkerRedwood 后臺(tái)任務(wù)實(shí)戰(zhàn)使用 exec 命令與 Faktory 構(gòu)建后臺(tái) Worker 導(dǎo)讀 本文基于 Redwood 官方 How To 文檔 doc后端前端Web框架開發(fā)工具Redwood 后臺(tái)任務(wù)實(shí)戰(zhàn)用 exec 命令與 Faktory 構(gòu)建后臺(tái) Workerversion 4.xRedwood 后臺(tái)任務(wù)實(shí)戰(zhàn)用 exec 命令與 Faktory 構(gòu)建后臺(tái) Workerversion 4.x 本文是一份面向 Redwood 應(yīng)用開發(fā)者后端前端Web框架開發(fā)工具創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考