如何把数据集变成自行运行的工作流

数据集本身毫无用处,直到有东西按时读取它、判断发生了什么变化,并采取行动。下面讲的是如何从一份你手动核对的文件,变成一个会自己核对的工作流。
贯穿全文的例子是价格监控:跟踪几件商品,发现某个价格波动时,在它造成损失之前通知相关的人。这个形状适用于任何有节奏的数据。
一句话要点
- 选一个变化节奏可预测的来源。
- 在入口处只清洗一次,让后面每一步都能信任它。
- 先算出结论,再按结论分支,而不是按原始值分支。
- 在任何不可撤销的动作前放一个人工审批。
- 把结果写回去,让下一次运行知道上一次做了什么。
六个步骤
| 步骤 | 做什么 | 为什么需要 |
|---|---|---|
| 1. 定时 | 每小时触发一次 | 节拍。没人需要记得启动 |
| 2. 抓取 | 实时读取来源 | 新鲜数据从这里进来 |
| 3. 清洗 | 每次都整理成相同的少数字段 | 下游不必再猜 |
| 4. 查询 | 检查这条记录以前见过没有 | 防重复,同时给出上一次的数值 |
| 5. 判断 | 波动是否超过 5%? | 真正的问题 |
| 6. 审批后行动 | 人确认之后,才发出告警并写入 | 不可撤销的部分,受控 |

整个构建在一张画布上:从左边的每小时触发器,到右边经审批的写入。
第 1 步:选一个有节拍的来源
自动化那些变化节奏你能说得出来的数据。不是「每周」,而是「每周一上午 9 点前,每个供应商一份 CSV,通过邮件发来」。这种精确度决定了你的触发器。
如果来源几乎不变,你要的不是工作流,而是一次查询,省下这份力气。
第 2、3 步:抓取,然后只清洗一次
原始来源都很乱。列名会漂移,日期有三种格式,一个供应商写「单价」,另一个写「每件价格」。
只在一个地方清洗,就在数据进来的位置。先确定你想要的形状(价格监控就是:商品、价格、货币、观察时间),再让每个来源都只产出这个形状。之后所有步骤都会变简单,因为它们可以信任输入。
有个几乎人人踩过的坑:失败的抓取常常伪装成成功。很多服务会把错误信息装在一个完全正常的响应里返回。在往下传之前,先确认拿回来的确实是数据,否则故障会静悄悄地穿过整个工作流。
第 4、5 步:先判断,再分支
工作流的目的是一个决定,所以要把这个决定写明白。
陷阱在于按原始值分支。你关心的不是价格是 12.40,而是它是否比上次上涨超过了你的容忍度。先算出这个,再按结果分支。
这里还有很实际的一面。看上去像数字的过滤条件,底层常常按文本比较,而文本的排序和数字不同:「100」排在「9」前面。于是「价格大于 9」的过滤可能悄悄漏掉你真正关心的 100。取出上一次的值,在一个明确的判断步骤里做运算,然后按它分支。
第 6 步:给不可撤销的动作加闸
最后一步应当做点真事:发告警、更新行、开工单、准备订单。
当这个动作代价高或不可回头时,前面放一个人工审批。运行会暂停、等待某个人,然后从停住的位置继续。便宜且可撤销的动作可以无人值守;任何触达客户或花钱的动作都要过闸。
关于暂停有两点值得知道。重复审批不会出问题:第一次的答复算数。下一次定时运行也不会碾过一个还在被思考的决定:每次运行保留自己的结果。
让重复运行安全的那一道保护
每小时触发意味着每小时重复同一次读取。没有保护,它每小时插入同一行,表里很快堆满重复数据。
在任何工具上都适用的解法:先查、再判断、后写入。先查这条记录。计数为零说明是新的,就写入;否则说明已存在,就更新。当同一条记录可能被重复读取时,绝不无条件插入。
这次查询一举两得:它既是防重复的保护,也是上一次数值的来源,而后者正是让「有没有变动?」这个问题可回答的前提。
会耗掉一个下午的四个陷阱
| 陷阱 | 你看到的现象 | 实际发生了什么 |
|---|---|---|
| 静默的空结果 | 某一步什么都没返回,也没有报错 | 数据比你预期的多嵌套了一层 |
| 看起来正常的失败抓取 | 下游全都是错的 | 错误装在一个正常响应里回来了 |
| 数字被当作文本比较 | 阈值悄悄漏掉了一些情况 | 「100」排在「9」前面 |
| 每小时产生重复行 | 表无止境地变大 | 写入前缺少「先查」保护 |
这些情况都不会抛出错误,这正是它们要耗掉一个下午的原因。
上线前逐条分支验证
不要只跑通顺路径就上线。刻意制造每一种情况,检查工作流实际做了什么。
| 测试 | 你制造什么 | 应该发生什么 |
|---|---|---|
| 新记录 | 一条没有历史的记录 | 恰好写入一行 |
| 无变化 | 已知记录,价格稳定 | 不发送、不写入 |
| 真实变化 | 已知记录,价格上涨 10% | 运行暂停等待审批 |
| 拒绝 | 拒绝这次审批 | 不告警,也不写入 |
| 跑两次 | 再次触发定时 | 行数保持不变 |
如果「真实变化」这一条没有暂停就跑完了,说明你的阈值是在你没打算的地方被求值的。这种故障值得在上线前抓住,而不是之后。
常见问题
它应该多久跑一次?
跟随来源的节奏。价格按小时,报表按天,供应商文件按周。跑得比数据变化更频繁,只会消耗调用量而得不到任何新信息。
历史数据放在哪里?
放在工作流自己读写的一张表里。这正是把一串独立运行变成有记忆的系统的关键:它知道自己处理过什么,也有昨天的数值可供比较。
如果运行中途失败会怎样?
运行会停在失败的那一步,记录会显示是哪一步、它收到了什么。你修那一步再重跑,而不是对整体做推理。
真的需要人在环节里吗?
只要是不可撤销的动作,就需要,至少在你建立信任之前。因一次解析错误就自动发送,正是自动化名声变差的原因。先保留这道闸,等证据支持时再撤掉。
下一步
挑一个你本来就每周手动核对的来源。写下它支撑的决定、你用的阈值,以及触发时你会做什么。这就是工作流,而你已经设计好了。接着看 该记录些什么,以便对它做过的事负责。