影刀RPA工程实战:自动化流程的版本控制、灰度发布与线上回滚体系

影刀RPA工程实战:自动化流程的版本控制、灰度发布与线上回滚体系

流程改了三个步骤,上线后把一百家店铺的价格全部调错。
这种事故只要经历过一次,就会把发布流程刻进骨头里。

我们在做店群自动化的过程中,经历过一段特别混乱的时期。影刀的流程文件用微信传来传去,文件名里带着日期和修改人——采集_张三_0518_fix.flow——哪个是最新版本没人说得清。一台执行机上一个版本,另一台又是另一个版本,出了Bug根本不知道是哪次改动引入的。

这不是影刀的锅,而是我们根本没把RPA流程当成软件交付来看待。

后来我们把自动化流程的发布,完全按照后端服务的CI/CD标准来设计,才真正告别了那种失控感。这篇文章就是这套体系的完整还原。


一、把影刀流程当成代码来管

picture.image 影刀的流程文件是一个二进制或者特定格式的打包文件(取决于版本),没办法直接做文本diff,这是最大的拦路虎。但我们不需要在流程文件内部做diff,只需要在版本层面做管理和追溯。

我们做的第一件事,就是强制所有流程文件必须走Git托管。虽然不能逐行对比流程里的拖拽节点,但可以做到:

  • 每个版本有唯一的commit hash,版本号不可篡改
  • 每次修改都有提交记录和说明
  • 版本可以通过CI打包为一个可部署的制品

picture.image

  • 任意历史版本随时可查可取

影刀的流程文件直接放在仓库里,配合一个metadata.json描述流程的元信息:

{
  "flow_name": "temu_order_collect",
  "version": "1.3.2",
  
![picture.image](https://p6-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/111ad7c7191849e5a3d3f912714bbacd~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1780416851&x-signature=pq7U5AKnoka5ZIY3zGhKf7kdCCg%3D)
  "platform": "temu",
  "safety_level": "safe",
  "author": "林焱",
  "commit": "a3f2b1c",
  "dependencies": {
    "browser_type": "chromium",
    "min_browser_pool_version": "2.1.0"
  },
  
![picture.image](https://p6-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/5308fd8259d84ecbb57d5c6ab5cc6c11~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1780416851&x-signature=V3sdjP%2BfMpo%2FwOlihA4YO0Y4pmo%3D)
  "change_log": "修复订单列表分页采集遗漏的问题"
}

这个元信息文件随着流程文件一起提交,Git标签自动与version对齐,CI在构建时校验一致性,不一致则构建失败。这样我们就有了一个可靠的单点真相来源。


picture.image

二、制品管理与部署包结构

picture.image 流程文件本身是不能直接部署的,因为线上执行需要配合环境参数、依赖声明、前置脚本。所以我们定义了一个标准的自动化流程制品包结构:

temu_order_collect_1.3.2/
├── flow/
│   └── main.flow
├── config/
│   ├── metadata.json
│   └── runtime_params_template.json
├── scripts/
│   ├── pre_check.py
│   └── post_cleanup.py
└── resources/
    └── selector_config.yaml

runtime_params_template.json 是运行时参数模板,定义了该流程需要哪些外部参数(店铺ID、时间范围等),执行节点在启动流程前会用实际值渲染这个模板。

制品包在CI里打包成zip,上传到内部的制品仓库,调度中心在分配任务时根据流程名和版本号拉取对应的制品包,解压到执行机的临时目录,然后调用影刀命令行执行其中的main.flow

这样做有一个非常大的好处:流程的运行环境与流程本身解耦了。同样的流程制品,可以在任意执行机上跑,只要执行机的基础环境满足依赖声明。


三、灰度发布的完整流水线

我们给每一个流程定义了四个发布阶段,必须逐阶段通过验证才能走向下一个。

阶段一:单店铺验证

新流程上线,先在 canary_shop(一台专用于验证的测试店铺,不涉及真实业务)上跑一轮。验证内容不只是流程能否跑完,还包括:

  • 所有关键元素是否定位成功
  • 执行时间是否在合理范围
  • 有无异常日志
  • 操作结果是否正确(与手工操作结果比对)

这一步由CI自动触发,跑完后生成验证报告,通过则自动进入阶段二。

阶段二:小批量灰度

选3~5个真实店铺,将它们任务路由到的流程版本切换为新版本。调度中心的路由器根据店铺ID查找灰度配置,决定使用哪个流程版本。

灰度期间,我们重点监控这些店铺的任务成功率、平均耗时、业务结果数据是否出现异常波动。如果有任何一项指标偏离基线超过20%,灰度自动暂停,触发回滚检查。

def should_use_canary_version(shop_id: str, flow_name: str) -> bool:
    canary_config = redis.hgetall(f"canary:{flow_name}")
    if not canary_config:
        return False
    canary_shop_ids = canary_config.get("shop_ids", "").split(",")
    return shop_id in canary_shop_ids

这段逻辑看起来简单,但它卡在调度中心每次分配任务时都会执行,是灰度的核心开关。canary配置存储在Redis里,可以动态调整灰度范围而不需要重启任何服务。

阶段三:扩大灰度

小批量跑满一个业务周期(通常是24小时,覆盖一天的完整运营节奏)且无异常后,灰度比例扩大到30%50%的店铺。这个阶段会持续23个业务周期,确保不同时间段、不同数据量下都稳定。

阶段四:全量发布

全量后保留旧版本制品一周,随时可回滚。全量发布的同时,旧版本在制品仓库中标记为 deprecated,不再接受新任务但已有任务不受影响。


四、回滚机制设计:不只是换个文件

回滚这个词说起来简单,做起来全是细节。

我们在实践中最惨痛的教训是:只回滚了流程文件,没回滚数据结构的变化,导致更严重的脏数据。

例如有一个流程v1.4在采集订单时,为了优化性能,把采集结果写到了一个新的Redis Key结构里,旧版本流程读的是旧结构。灰度回滚到v1.3后,v1.3试图从新结构里读数据,解析失败,全部报错。

后来我们的回滚操作被设计成了一个事务性的流程,包含以下步骤:

  1. 冻结新版本的任务队列:调度中心停止向该流程类型的任务推送新版本,所有新任务走旧版本。
  2. 等待进行中的新版本任务完成或超时:不做强制kill,避免留下半成品数据。
  3. 数据兼容性检查:如果新版本修改了数据落盘结构,检查旧版本是否能正常读取当前数据。如果不能,需要执行一次数据回迁脚本(这部分通常在发布前就预备好)。
  4. 切换路由配置:将灰度配置里的版本号指向旧版本,清理Redis里的新版本缓存。
  5. 验证旧版本可用性:在canary店铺跑一轮旧版本,确保切换成功。
  6. 解除冻结:恢复任务下发。

这些步骤在一个Python脚本里编排,依赖人工触发但执行过程全自动,每一步都有日志和状态更新,出错了也知道卡在哪一步。

回滚不是紧急情况下的手忙脚乱。
它应该是一次演练过无数遍的标准化操作。


五、多版本共存的能力边界

在灰度期间,同一个流程的多个版本是同时运行的。这就要求我们在设计流程时遵守一条铁律:流程必须保证向后兼容性,至少在相邻版本之间。

具体约束包括:

  • 流程的输入参数模板只能新增字段,不能删除或修改已有字段的类型
  • 输出的数据格式(写入数据库的表结构、Redis Key模式)如果变更,新版本必须同时兼容旧格式的读取,旧版本回滚时也要能容忍新格式的存在
  • 店铺环境的 user-data-dir 不能被新版本做出不可逆的修改(比如安装了旧版本不支持的浏览器扩展)

我们曾经打破过最后一条规则,在一个新版本流程里给浏览器环境装了一个辅助插件。灰度回滚后,旧版本启动时发现浏览器里多了个不认识的东西,直接导致登录态校验逻辑错乱,好几个店铺被迫重新登录。那一次之后,我们任何涉及浏览器环境变更的发布,都要求额外评估回滚的环境修复成本。


六、CI/CD的落地形态

我们用GitLab CI来编排整个流程的持续集成和部署。不是花哨的流水线,只做几件实在事:

stages:
  - validate
  - build
  - canary_test
  - deploy_gray
  - deploy_full

validate:
  stage: validate
  script:
    - python ci/validate_metadata.py
    - python ci/check_flow_naming.py

build:
  stage: build
  script:
    - python ci/create_artifact.py --version $CI_COMMIT_TAG
  artifacts:
    paths:
      - artifact.zip

canary_test:
  stage: canary_test
  script:
    - python ci/push_to_canary.py --artifact artifact.zip --shop canary_shop_01
    - python ci/wait_and_verify.py --timeout 600

deploy_gray:
  stage: deploy_gray
  when: manual
  script:
    - python ci/set_canary_config.py --percent 10

deploy_full:
  stage: deploy_full
  when: manual
  script:
    - python ci/set_canary_config.py --percent 100

每一个阶段都有明确的门禁。validate阶段检查元数据完整性和命名规范,canary_test在测试店铺跑真实的自动化流程并等待验证结果。灰度发布和全量发布都是手动触发,因为这个决策目前我们还不敢完全交给机器。


七、那些在发布流程上栽过的跟头

跟头一:流程文件体积膨胀导致制品拉取超时

一些流程里嵌入了大量的截图和资源文件,单个制品包膨胀到200MB以上,执行节点每次从制品仓库下载都要一分多钟,任务整体耗时被严重拉长。后来我们强制流程设计规范:所有静态资源外置到独立的资源服务,流程里只保留引用链接,制品包控制在10MB以内。

跟头二:灰度比例配置错误引发全量切换

有一次运维在设置灰度比例时,误把小数填成了整数—— percent: 10 写成了 percent: 100——瞬间全部店铺都切到了未充分验证的新版本,半个小时不到出了问题,影响了一百多个店铺。从那以后,灰度配置的修改必须经过双人复核,并且在调度中心加了一个硬限制:灰度比例单次上调幅度不得超过30%,超过则需要分步操作。

跟头三:旧版本制品被误删,回滚时发现zip不存在

制品仓库配置了定期清理策略,本意是清理一年前的旧版本,结果因为时间戳配置错误,把三个月前的历史版本全清了。好在Git仓库里还保留着源文件,紧急重新打包才完成回滚。现在我们的制品仓库对标记为 activestandby 的版本永久保留,只清理明确标记 archived 的版本。


八、发布与业务的协同节奏

店群自动化有一个特点:运营有固定的业务节奏。比如TEMU的促销活动周期、TikTok Shop的直播高峰时段。在这些关键时间窗口内,我们是严禁做流程发布的。

我们在调度中心加了一个发布日历模块,标注了每个平台的关键业务周期。提交灰度或全量发布时,系统会自动检查当前是否处于禁发期,如果在禁发期,直接阻止发布,只能排队等到窗口结束。

这个功能拯救了我们很多次。有次一个同事周五下午想发一个新版本的批量上货流程,被发布日历拦住了——因为那个周末正好是大促,任何异常都可能导致巨大损失。他当时很不理解,觉得小改动没问题。但周一数据出来时,我们发现同行的确有店铺因为在促销期间自动化出错而被平台处罚。那之后,发布日历成了团队默认遵守的规则。


九、这套体系还缺什么

坦率说,我们的流程版本管理还有很多粗糙的地方。最大的痛点是流程内部逻辑的diff能力缺失——当流程出问题时,我们只能靠发布说明和提交记录来猜哪里改了,没有办法像代码一样精确对比两个版本的节点变化。

目前我们正在尝试把影刀流程的关键逻辑(元素选择器、条件分支、循环结构)导出为一种中间描述语言,然后用这个中间语言做diff和影响分析。不过这个方向还处于探索阶段,尚未正式上线。

另外一个缺口是自动化回滚后的数据修复。现在对数据结构不兼容的情况,我们依赖手动执行数据回迁脚本,希望能演进到自动检测并触发修复的机制。


十、写在最后

很多人觉得RPA流程就是拖拖拽拽,改改就能用,不需要搞版本管理、发布流水线这么“重”的东西。但我们的血泪教训一再证明:当自动化流程承载的是真实业务,哪怕它只是一个脚本,也必须用交付软件的严谨来对待它。

流程不是写出来就完事了。它是活的,会迭代,会出Bug,会有多个版本同时跑在线上。只有把从开发到发布的整条链路工程化,才能让每次改动都心中有底,出了问题退得回去。

敬畏发布,就是敬畏业务。
这条原则,放在任何自动化体系里都不为过。

作者:林焱
一个每次点击“发布”按钮前都要再三确认的工程师

0
0
0
0
评论
未登录
暂无评论