Skip to content

第 15 章 · 部署:Node.js 与 Cloudflare Workers

本章目标:把 Flue agent 部署到两大官方目标——Node.js 长驻服务与 Cloudflare Workers 边缘运行时,理解各自的持久化与密钥管理差异。

15.1 部署目标的共同前提

无论部署到哪里,都要先解决三件事:

text
① 构建产物(@flue/vite 负责打包 agent 代码)
② Provider 密钥注入(环境变量 / Secrets)
③ 持久化存储(Durability 状态放哪)
typescript
// vite.config.ts — 两种目标的构建配置入口
import { flue } from '@flue/vite';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [flue()], // 处理 'use agent' 指令与运行时打包
});

15.2 Node.js 部署

Node 是最直接的长期运行目标:进程常驻,恢复在启动时自动进行。

typescript
// src/main.ts — 生产入口
import { createApp } from '@flue/runtime/node';
import { postgresAdapter } from '@flue/postgres';
import { Pool } from 'pg';

const app = createApp({
  // 生产必须外接持久化,进程重启才能恢复受理中的会话
  database: postgresAdapter({
    pool: new Pool({ connectionString: process.env.DATABASE_URL }),
  }),
});

app.listen(process.env.PORT ?? 3000);
bash
# 构建并运行
npm run build          # vite build
NODE_ENV=production node dist/main.js

# 用 PM2 守护(或 systemd / Docker)
pm2 start dist/main.js --name flue-bot
dockerfile
# Dockerfile — 容器化 Node 部署
FROM node:22-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY dist ./dist
# 密钥通过环境变量注入,绝不写进镜像
ENV NODE_ENV=production
CMD ["node", "dist/main.js"]

15.3 Cloudflare Workers 部署

Workers 是无服务器 isolate:没有常驻进程,靠请求与闹钟唤醒,持久化天然走数据库。

typescript
// src/worker.ts — Workers 入口
import { createWorkerApp } from '@flue/runtime/cloudflare';

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // env 中拿到绑定:数据库(D1/Hyperdrive)与 Secrets
    const app = createWorkerApp({ env });
    return app.fetch(request);
  },

  // cron 闹钟:定期推进未完结的受理(见第 12 章恢复行为)
  async scheduled(_ctrl: ScheduledController, env: Env) {
    const app = createWorkerApp({ env });
    await app.resumePending();
  },
};
toml
# wrangler.toml — Workers 配置
name = "flue-agent"
main = "src/worker.ts"
compatibility_date = "2026-01-01"

[triggers]
crons = ["*/5 * * * *"]   # 每 5 分钟唤醒一次做恢复检查
bash
npx wrangler deploy

15.4 密钥与环境变量

两个目标的注入机制不同,但读取方式统一:

目标本地开发生产注入
Node.js.env 文件系统环境变量 / Docker ENV / K8s Secret
Workers.dev.vars 文件wrangler secret put XXX
bash
# Workers 密钥注入(交互式,不落盘)
npx wrangler secret put ANTHROPIC_API_KEY
npx wrangler secret put DATABASE_URL
typescript
// 统一读取:代码不感知部署目标差异
// Node: process.env.XXX;Workers: env.XXX(由适配器归一化)
const apiKey = env.ANTHROPIC_API_KEY ?? process.env.ANTHROPIC_API_KEY;
if (!apiKey) throw new Error('missing ANTHROPIC_API_KEY');

两个目标的本质差异

Node:进程常驻 → 崩溃后由重启触发恢复;Workers:isolate 随时回收 → 由下一次请求或 cron 触发恢复。业务代码几乎不变,但运维心智不同。

15.5 本章小结

  • 共同前提:@flue/vite 构建、密钥注入、外接持久化;
  • Node 长驻:postgresAdapter + PM2/Docker 守护,重启即恢复;
  • Workers 无服务器:createWorkerApp({ env }) + cron 闹钟做恢复检查;
  • 密钥本地用 .env/.dev.vars,生产用系统环境变量或 wrangler secret put

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. Node.js 与 Cloudflare Workers 部署 Flue 时,恢复(recovery)的触发方式有何不同?

2. 在 Cloudflare Workers 上管理生产密钥的正确方式是?

3. 为什么 Workers 部署通常要配置 cron trigger?

4. 关于 @flue/vite 在部署中的作用,正确的说法是?

🛠️ 动手实践

  1. 把第 11 章的 Triage agent 部署为 Node 服务,用 PM2 守护并验证 kill 后自动拉起。
  2. 部署同一 agent 到 Cloudflare Workers,配置 5 分钟 cron,在 Dashboard 观察唤醒日志。
  3. 分别用 .envwrangler secret put 注入密钥,写一份团队密钥管理清单。