跳转到主要内容
自动化是应用中自动运行的部分——按计划运行,或在外部服务发送事件时运行。 你在 kazzle.config.ts 中的 process 组件上声明它们。一个组件可以包含任意数量的触发器。

结构

{
  name: 'events',
  type: 'process',
  path: './components/events/index.ts',
  processMode: 'persistent', // or 'triggered'
  triggers: [
    { name: 'daily-digest', kind: 'schedule', schedule: '0 9 * * *', path: '/cron/daily-digest' },
    { name: 'stripe',       kind: 'webhook',                          path: '/webhook/stripe' },
  ],
}
这里发生了两件事:
  • processMode 选择生命周期——长期运行的服务器,或每个触发器运行一次。
  • triggers[] 列出应该触发此组件的事件
这两部分是独立的。持久服务器可以有 cron。临时进程可以有 webhook。选择适合工作负载的生命周期,然后附加任意数量的触发器。

processMode

模式运行内容何时使用
persistent(默认)长期运行的 HTTP 服务器。触发器被 POST 到它。组件已经提供 HTTP 服务,或在内存中保持状态(队列、websocket、缓存)。
triggered每个触发器生成入口脚本并退出。纯后台任务——夜间清理、单个 Stripe webhook 处理器等。无空闲服务器。

触发器

每个触发器有一个 name(在组件内唯一)、一个 kind,以及——取决于模式——一个 schedule 和/或 path
字段何时必需说明
name总是用作 webhook URL 段和日志中。使用 kebab-case。
kind总是'schedule''webhook'
schedulekind: 'schedule'5 字段 cron 表达式。分钟分辨率是最小单位。
pathprocessMode: 'persistent'触发器到达的服务器上的 HTTP 路由。

持久模式——HTTP 到服务器

当持久组件的触发器触发时,Kazzle 在声明的 path 处 POST 到你的服务器。请求包含:
标头说明
Authorization: Bearer ${KAZZLE_TRIGGER_SECRET}验证这个。拒绝不匹配的调用。
x-kazzle-trigger-name清单中触发器的 name
x-kazzle-trigger-run-id用于日志关联的不透明 ID。
x-kazzle-triggered-bycron | webhook | manual
对于 webhook 触发器,原始请求体作为 POST 体转发。对于计划触发器,体为空。
// components/events/index.ts (persistent mode)
const TRIGGER_SECRET = process.env.KAZZLE_TRIGGER_SECRET ?? '';

Bun.serve({
  port: Number(process.env.PORT),
  hostname: process.env.HOST,
  async fetch(req) {
    const url = new URL(req.url);

    if (req.method === 'POST' && url.pathname === '/cron/daily-digest') {
      if (req.headers.get('authorization') !== `Bearer ${TRIGGER_SECRET}`) {
        return new Response('Unauthorized', { status: 401 });
      }
      await sendDigest();
      return Response.json({ ok: true });
    }

    if (req.method === 'POST' && url.pathname === '/webhook/stripe') {
      if (req.headers.get('authorization') !== `Bearer ${TRIGGER_SECRET}`) {
        return new Response('Unauthorized', { status: 401 });
      }
      const event = await req.json();
      await handleStripe(event);
      return Response.json({ ok: true });
    }

    return new Response('not found', { status: 404 });
  },
});

触发模式——每个触发器一次性

triggered 组件的触发器触发时,Kazzle 生成入口脚本并等待它退出。没有 path;脚本从环境变量了解哪个触发器触发。
环境变量
TRIGGER_NAME清单中触发器的 name
TRIGGERED_BYcron | webhook | manual
RUN_ID用于日志关联的不透明 ID。
WEBHOOK_PAYLOADJSON 体(仅 webhook 触发器)。
// components/events/index.ts (triggered mode)
const trigger = process.env.TRIGGER_NAME;
const runId = process.env.RUN_ID;

if (trigger === 'daily-digest') {
  await sendDigest();
} else if (trigger === 'stripe') {
  const event = JSON.parse(process.env.WEBHOOK_PAYLOAD ?? '{}');
  await handleStripe(event);
}

console.log(`run ${runId} done`);
触发组件在生产中没有空闲机器——它们按调用生成并在退出时关闭。

Webhook URL

POST https://api.kazzle.app/webhooks/{spaceId}/{appId}/{componentName}/{triggerName}
triggerName 段必须与该组件 triggers[] 中的 kind: 'webhook' 条目匹配。未知的触发器名称返回 404。

计划分辨率

Cron 表达式是 5 字段(分钟、小时、月份日期、月份、周几),分钟分辨率是最小单位。子分钟计划在清单验证时被拒绝。

运行如何被记录

每个触发器触发写入一个 process_runs 行,包含 trigger_nametriggered_byrun_id 和运行的退出状态。你可以从自己的代码查询这些,或在应用的运行视图中检查它们。

信用不足

失败的运行被记录和记录,但计划按其正常节奏继续运行——不稳定的运行永远不会禁用触发器。停止运行的唯一因素是信用:每个触发器触发都会针对空间的余额进行检查,当空间信用不足(或未设置计费)时,运行会被跳过并返回 402。这是自我恢复的——计划保持启用,充值后的下一次触发正常运行,无需手动恢复。

稍后添加自动化

简单的应用可以不带触发器开始,稍后获得它们——添加每日摘要、连接 Stripe、运行清理。组件的生命周期(processMode)和触发器(triggers[])是独立的,所以你可以更改它们而无需重写应用的其余部分。