ObjectOS
构建

流程与自动化

声明式业务逻辑 —— 无论是描述给 AI 还是用 TypeScript 编写,运行时执行的都是同一份产物。

流程与自动化

Flow 是你不写服务端就能表达业务逻辑的方式。每个 Flow 都是声明式元数据,由运行时执行 —— 与对象、视图一样。这意味着 Flow 会同时出现在 os diff、审计日志、Console 的流程构建器以及 AI Builder 中。

多数客户通过对 AI 提问来创建 Flow:

"当一个高优先级工单在 'new' 状态停留 30 分钟时,在 Slack 上通知经理。"

AI 会生成下面的 Flow。本页描述其结构,以便你阅读和编辑。

在 stack 中启用该能力:

export default defineStack({
  // ...
  requires: ['automation'],
});

三种流程类型

类型触发方式用于
Autolaunched记录变更(insert/update/delete)"用户注册时发欢迎邮件"
ScheduledCron 表达式或间隔"每晚 2 点标记过期任务"
Manual用户在 Console 点按钮,或 API 调用"审批发票"等 Action

Autolaunched:对记录变更做出反应

// src/flows/welcome_email.ts
import { defineFlow } from '@objectstack/spec';

export const welcomeEmail = defineFlow({
  name: 'welcome_email',
  type: 'autolaunched',
  trigger: {
    object: 'sys_user',
    when: 'after_insert',
  },
  steps: [
    {
      type: 'action',
      action: 'send_email',
      inputs: {
        to:      '{!trigger.record.email}',
        subject: 'Welcome to {!org.name}',
        body:    'Hi {!trigger.record.name}, welcome aboard.',
      },
    },
  ],
});

变量插值:{!trigger.record.<field>}{!org.<field>}{!user.<field>}{!step.<step-name>.output}condition: 块中使用 CEL 表达式。

触发时机:

when何时触发
before_insert写事务内、INSERT 之前
after_insert提交之后
before_update写事务内、UPDATE 之前
after_update提交之后
before_delete写事务内、DELETE 之前
after_delete提交之后

before_* 流程可以修改正在写入的记录(计算字段、归一化数据)。after_* 流程异步运行,可以调用慢的外部服务。

Scheduled:按时钟运行

export const nightlyCleanup = defineFlow({
  name: 'nightly_cleanup',
  type: 'scheduled',
  schedule: { cron: '0 2 * * *', timezone: 'America/New_York' },
  steps: [
    {
      type: 'query',
      query: { object: 'task', filter: 'status:open AND due_lt:now()' },
      output: 'stale',
    },
    {
      type: 'foreach',
      items: '{!step.stale}',
      do: [
        { type: 'update', record: '{!item.id}', fields: { status: 'overdue' } },
      ],
    },
  ],
});

@objectstack/service-job 能力承载 —— 见 Runtime Capabilities

Manual:Action 与审批

export const approveInvoice = defineFlow({
  name: 'approve_invoice',
  type: 'manual',
  inputs: {
    invoice_id: { type: 'lookup', reference: 'invoice', required: true },
    note:       { type: 'textarea' },
  },
  steps: [
    {
      type: 'update',
      record: '{!inputs.invoice_id}',
      fields: { status: 'approved', approved_by: '{!user.id}' },
    },
  ],
});

在 Console 中作为 Invoice 视图上的按钮暴露,或通过 REST 调用:

curl -X POST https://app.example.com/api/v1/actions/invoice/approve_invoice \
  -H 'Authorization: Bearer <token>' \
  -d '{"inputs": {"invoice_id": "inv_123", "note": "OK"}}'

步骤类型

步骤用途
query通过 ObjectQL 读取记录
create / update / delete写对象
action调用内置或插件注册的 Action(email、webhook、AI 调用……)
condition按 CEL 表达式分支
foreach遍历集合
parallel并发执行子步骤
wait暂停一段时长 / 至时间戳 / 至条件成立
subflow调用另一个 Flow
approval阻塞直至用户审批(需要 @objectstack/plugin-approvals)

条件与分支

{
  type: 'condition',
  when: 'trigger.record.amount > 10000',
  then: [
    { type: 'action', action: 'send_slack', inputs: { /* ... */ } },
  ],
  else: [
    { type: 'update', record: '{!trigger.record.id}', fields: { status: 'auto_approved' } },
  ],
}

错误处理

每个步骤接受:

{
  type: 'action',
  action: 'send_email',
  inputs: { /* ... */ },
  retry: { attempts: 3, backoffMs: 1000, multiplier: 2 },
  onError: 'continue' | 'fail' | 'rollback',
}

对于 autolaunched 的 before_* 流程,onError: 'fail'(默认)会终止原始写事务。对 after_* 流程,原始写已经提交,失败的流程运行会落到任务重试队列。

公式与表达式(CEL)

条件、动态字段值和过滤表达式都接受 CEL(Common Expression Language) —— 谷歌为安全表达式求值设计的语言:

'amount > 10000 && account.tier == "enterprise"'
'duration(now() - created_at) > duration("30d")'
'has(record.notes) && record.notes != ""'

CEL 是沙盒化的(无副作用、无 I/O)、服务端求值、并可在流程构建器中审计。

可视化构建器

Console 自带一个可视化流程构建器,它与声明式元数据来回往返 —— 非工程师可以编辑流程,序列化结果与你手写的 TypeScript 同形。

测试流程

os test --scenario "welcome email fires on signup"

限制与最佳实践

  • **保持 before-hook 简短。**它们会阻塞写事务。
  • **用 wait 代替长时运行的步骤。**休眠的流程会占用 worker;wait until 会把 worker 还回池里。
  • **用 parallel 跑独立步骤。**默认是顺序执行。
  • **幂等很重要。**重试可能让同一步骤跑两次;外部副作用应去重(用流程运行 id 作为键)。
  • **审计敏感的 Action。**改权限或删记录的流程自身也应记录到 sys_audit_log

下一步

On this page