条件:数据变化、阈值与时间
三类条件怎么写、怎么防止重复触发,以及为什么看门狗只能靠时间。

本课目标
读完这一课,你将能够
- 区分对象数据变化、阈值和时间三类条件,各举一个示例工厂的例子
- 写出带
when与cooldown的trigger.change,并说出它只看变化之后的对象 - 说出看门狗为什么只能用时间条件,并写出它的触发
对象数据条件:盯着一组对象
对象数据条件盯着一个对象集:对象加入集合、离开集合、在集合里被修改,或者定期对集合里的每个对象跑一遍。条件触发时,会把触发它的对象交给效果去用。
「加入集合」最容易误解。给对象集加一个筛选(状态 = 待处理),新建的对象算加入,状态刚改成「待处理」的旧对象也算;已经在集合里的对象再改别的属性,不算。所以它只在「进入」那一刻触发一次。
组织级自动化支持 objectsAdded、objectsModified、objectsRemoved 和 runOnAllObjects。应用工作流用 trigger.change:指定 Object Type,再写 when。对象新建或修改后,平台用变化后的对象求值;为真就开一次运行。每条变化最多触发一次,工作流自己的写入不会触发自己。
| 「加入集合」 | when 为真 | |
|---|---|---|
| 触发时机 | 对象进入集合的那一次 | 每次新建或修改后,条件都为真 |
| 看什么 | 变化前后的状态 | 只看变化之后的对象 object,另有 change(操作、来源、执行人、序号) |
| 防重复 | 进入才触发,天然一次 | cooldown,加上效果里的检查 |
阈值:跨过那条线,还是一直在线下
阈值条件拿一个指标和一个数比较。指标可以是一个属性,也可以是一组对象的汇总,比如一条产线上所有设备的最高温度。标准模型在指标越线时触发,回到线内时再记一次「恢复」。
在 AIDC 里,单个对象的阈值直接写进 when。示例工厂的④「设备振动超阈值」这样写;lastVibration 是本课给 machine 加的一个小属性,设备物联网每次同步写入最新读数,7.1 是示例阈值:
"trigger": {
"change": {
"type": "machine",
"when": "=object.lastVibration > 7.1",
"cooldown": "1d",
"input": { "machine_id": "=object.machineId" }
}
}
设备一直振动超标时,每次同步都会修改对象。工作流的 when 每次都为真,它不判断是否刚越线。因此要两道保险:
cooldown:同一个对象两次运行至少隔这么久,冷却期内的变化只推进游标,不开运行。- 效果里的检查:先查是否已有未完成的维保工单,有就什么都不做。
一组对象的汇总阈值,目前没有对应的条件类型:用定时触发加聚合查询算出汇总,在计算步骤里比较,再通知。
时间条件与看门狗
时间条件按时间表触发:每天、每周、每月,标准模型还支持 cron 表达式。它的下一次评估,要等上一次评估完成、效果排上队之后才排定,所以两次评估不会互相重叠。
应用工作流的 trigger.schedule 用 every 和 at。every 是 1–9,999 的整数加 m、h 或 d,最短 5 分钟。按天间隔才能配 at,时间按 UTC 的 HH:MM 写。组织级时间条件的 at 和 weekdays 按北京时间算。部署工作流时按频率分级检查:
小于 5 分钟
部署被拒绝。要实时,就用 change。
5 分钟到 1 小时
高频,一定告警。每 5 分钟一次,一个月是 8,640 次运行。
超过 1 小时
中频只提示次数;一天一次起是正常。
只有时间本身就是条件的事才用它:日报(⑤)、月底对账,还有看门狗(⑥)。看门狗盯的是「该来的数据没来」:数据不来就没有变化,change 永远不会响,只有时间能发现。
feedStatus 是本课给示例工厂加的小对象,ERP 发布端每一轮把当前时间写进它的 syncedAt。⑥ 每小时查它一次,超过 2 小时就发邮件。下面是清单的关键部分:
{
"slug": "erp-watchdog",
"limits": { "notificationsPerDay": 10 },
"workflow": {
"trigger": { "schedule": { "every": "1h" } },
"steps": [
{ "id": "feed", "kind": "use", "title": "ERP heartbeat",
"use": "factory-ops/erp_heartbeat", "with": {} },
{ "id": "check", "kind": "compute", "title": "How old is it",
"fields": {
"hours": "=hoursSince(steps.feed.row.syncedAt)",
"stale": "=hours == null || hours > 2"
} },
{ "id": "mail", "kind": "notify", "title": "Alert the planner",
"when": "=steps.check.stale",
"to": ["planner@example.com"],
"subject": "ERP data is {{ steps.check.hours }} hours old",
"body": "No ERP sync has arrived for over two hours. Check the publisher before trusting stock and order figures.",
"dedupe": "=today()", "cooldown": "6h" }
],
"output": { "hours": "=steps.check.hours" }
}
}
hoursSince 算数据有多久没更新;读不到心跳时得到 null,同样算过期。dedupe 与 cooldown 让同一天里最多每 6 小时提醒一次。每小时属于高频,部署会有告警,这里时间本身就是条件,可以接受;要放宽就把 every 改成 2h。
逐个对象,还是整批
change 触发时,input 决定一次运行处理什么。
input 映射到对象 | input 留空 | |
|---|---|---|
| 一次运行 | 处理一个对象 | 同一批变化只开一次运行 |
| 适合 | 对每个对象各做一件事:为一个物料起草一张订单 | 对全体做一次检查或汇总 |
| 标准模型里的说法 | 逐个对象执行 | 一次给全部对象执行 |
一次数据快照改了很多对象,留空的写法同一批只开一次运行,而不是同样的检查跑很多遍。频繁更新、又只需要汇总的检查,用留空的写法,或者干脆改成定时。
要点
- AIDC 的
trigger.change只看变化之后的对象,when每次为真就触发一次,没有「刚刚跌破」的概念。 - 防重复用两道保险:
cooldown,和效果里的「已经处理过了吗」的检查。 - 定时只留给时间本身就是条件的事;小于 5 分钟拒收,5 分钟到 1 小时一定告警。
- 看门狗盯「该来没来」:没有数据就没有变化,只有定时触发能发现。
input映射到对象是一个对象一次运行,留空是一批变化一次运行。
练一练
为示例工厂写条件
三个练习,都只用本课讲到的写法。
为①「销售订单确认且物料齐套」写 trigger.change。when 只能看变化的那个对象:「物料齐套」应该写在条件里,还是放到效果的查询与计算步骤里?为什么?
保持 2 小时的阈值,把 ⑥ 的 every 放宽到 2h。数据断了之后,最坏要多久才会告警?
一个每 15 分钟一次的定时,按 30 天算一个月跑多少次?它落在哪一级?它能不能改成数据变化触发?
小测
选一个答案,马上看解析。
Q1「ERP 两小时没来数据就告警」,为什么不能用 trigger.change?
看门狗要发现的正是「没有变化」。所以它用 trigger.schedule,并且要遵守频率分级。
Q2物料一直低于安全库存,ERP 每次同步都会修改它。只写 when: onHandQty < safetyStockQty 会怎样?
工作流的 when 只看变化后的对象,不判断是否刚越线。组织级的 objectsAdded 才表示加入对象集。
Q3下面哪个 schedule 会被部署直接拒收?
小于 5 分钟拒收,要实时就用 change。5m 是高频,只告警不拦;7d 是合法间隔,但不是最长间隔。