AI多Agent协作系统实战(五十三):同一套系统,Linux沉默,Windows刷屏

系列第53篇 | 一个CRLF让Linux的定时报告从没跑成功,一个每分钟cron让Windows刷了9小时------"不要各自为政"后的统一之旅

背景

"你把61启动,然后两边对比一下,不要各自为政。"

用户一句话,把两台服务器拉到了同一张手术台上。61号(Linux,生产服务器)和62号(Windows,测试服务器)跑着同一个产品------AI数字员工队伍------按理说,它们的定时报告机制应该长得一模一样。

可它们不是。

61号沉默得像块石头,62号刷屏刷得人想砸键盘。而这两台机器,跑的是同一个版本的产品。

我登上去,把两边摆在一起。

问题1:61号,一个换行符让脚本"死"在启动前

先看61号(Linux)的定时任务:

arduino 复制代码
任务: fd1356414b27  "定时统筹汇报"
频率: */3 * * * *        ← 每3分钟
脚本: task_monitor.sh    ← bash脚本
状态: error
错误: /vol1/1000/ai-team-collab/hermes/scripts/task_monitor.sh: line 9: $'\r': command not found
      line 13: $'\r': command not found
      line 30: export: `WS_DIR\n': not a valid identifier
      line 51: syntax error: unexpected end of file

$'\r' ------回车符。这个bash脚本里每一行的行尾,都藏着一个Windows的\r(回车),Linux的bash看到它直接懵了:command not foundsyntax error

为什么bash脚本里会有Windows换行?因为它是从Windows机器上"同步"过去的 。昨天我们做跨平台版本同步,把62号(Windows)上的task_monitor.sh直接复制到了61号(Linux)------Windows编辑器存文件默认CRLF(回车+换行),Linux只要LF(换行)。一个字符的差别,整个脚本从部署那天起就没跑成功过一次

61号的定时报告,一直是静默 的------不是"没任务所以静默",是脚本压根跑不起来。而系统毫无察觉,cron每3分钟"成功"地调用一次,脚本每3分钟"成功"地报一次错。

问题2:62号,每分钟刷一条,9小时558次

再看62号(Windows):

makefile 复制代码
任务: fd1356414b27  "定时统筹汇报"
频率: * * * * *         ← 每分钟!
脚本: task_monitor_report_cron.py  ← python脚本
状态: ok
执行次数: completed=558

62号跑的是python版脚本,每分钟 触发一次,每次生成报告就发飞书。558次------9个多小时,每分钟一条。用户被刷屏到忍无可忍:"定时报告又在重复了。"

为什么每分钟?为什么每次都发?------因为62号的cron频率配的是每分钟,而且脚本没有去重:只要有任务在跑,报告就有内容,有内容就发,发了再发。

一边是永远沉默 ,一边是永远刷屏------同一个功能,两个极端。

问题3:同一个功能,两套实现

把两边摆在一起看,差异触目惊心:

scss 复制代码
┌─────┬──────────────────┬──────────────────┐
│     │ 61 (Linux)       │ 62 (Windows)     │
├─────┼──────────────────┼──────────────────┤
│频率 │ */3 每3分钟      │ * * * * * 每分钟 │
│脚本 │ task_monitor.sh  │ task_monitor_    │
│     │ (bash版)         │ report_cron.py   │
│     │                  │ (python版)       │
│状态 │ ❌ error(CRLF)   │ ✅ ok但刷屏      │
│行为 │ 沉默8小时        │ 每分钟发1条      │
└─────┴──────────────────┴──────────────────┘

同一个"定时统筹汇报"功能,两台机器用不同的脚本、不同的频率、不同的行为实现 。这就是"各自为政"的典型症状:跨平台版本同步时,Windows的脚本换行进了Linux;两边又各自维护了不同版本的cron脚本;频率一个3分钟一个1分钟------没有一个人对"标准答案"负责

用户说得对:"不要各自为政,两边都要保持一致,后续好维护。"

修复:统一为一份脚本

方案很明确:同一份脚本,两个平台通用

把62号验证过的python版(task_monitor_report_cron.py)升级成跨平台统一版:

python 复制代码
# 平台python: Linux用/usr/bin/python3(pyarmor兼容), Windows用sys.executable
if os.name == 'posix':
    PY = '/usr/bin/python3' if os.path.exists('/usr/bin/python3') else sys.executable
else:
    PY = sys.executable

# 目录自适应: 61脚本在hermes/scripts, 62在app/scripts------都能找到
cands = [
    os.path.join(HERE, '..', '..', 'app', 'scripts'),
    HERE,
    r'D:\ai-team-collab\app\scripts',
]

再加上之前踩坑攒下的三件套:

  1. 去重hash------报告正文不变就静默(标题时间戳排除在外)
  2. 唤醒兜底------检测inbox有未处理任务就唤醒agent
  3. 动态路径 ------工作区从paths.json读,不再硬编码/vol1/1000D:\

然后两边一起换:频率统一*/3,脚本统一同一份文件。

验证:一边从error变ok,一边从刷屏变静默

61号(Linux)先改:

yaml 复制代码
cron: */3 * * * * -> task_monitor_report_cron.py | status: ok

error → ok。那个被CRLF"封印"了8小时的脚本,换成python版后第一次真正跑通。顺手把task_monitor.sh转成LF格式留作备份------但主驱动已经是统一版python脚本了。

62号(Windows)改完频率+去重:

makefile 复制代码
run1: 741B(发送------有变化)
run2:   0B(静默------内容没变)

从每分钟刷屏,到只有状态变化才发。用户看到报告"固定"在一个时间点,问"为什么固定了"------其实那是去重生效了:任务没进展就不打扰。

最后验证两边路径解析------同一套加密代码,各自读出自己的路径

bash 复制代码
62: TASK_DIR: D:\workspace\claw-sync\task
61: TASK_DIR: /vol1/1000/workspace/claw-sync/task

经验总结

  1. 跨平台同步,换行符是第一道坎 。Windows的CRLF进了Linux的bash脚本,等于给脚本下了"启动即报错"的诅咒。同步文本文件(脚本/配置)前,先确认行尾格式:file xxx.shcat -A xxx.sh | head,一眼看穿。

  2. "各自为政"是双机系统的头号敌人 。同一个功能,两台机器两套实现、两个频率、两种行为------出问题时一个沉默一个刷屏,你根本不知道"标准答案"是什么。统一脚本 + 统一频率 + 统一行为,这是"保持一致"的最低标准。

  3. error和ok一样危险 。61号的状态是error,但它"安静地错了8小时"------cron照常调用,日志照常记录,没有任何人发现。静默失效比大声报错可怕得多:报错你会去修,沉默你会以为一切正常。定时任务跑起来后,至少看一次真实输出,别只看状态字段。

  4. 一个动作,一个标准,一份代码。同一份脚本在不同平台各自解析路径(paths.json),比"每个平台维护一份脚本"强一万倍------改一处,两边生效;少一处,多一分一致。

Linux沉默,Windows刷屏------不是系统坏了,是没有人规定"标准答案"。

相关推荐
那咋乎吧22 分钟前
TCP状态机11个状态全梳理(以java netty 结合bio,nio, io多路复用模型为线索在linux上梳理)
后端
用户78136671144530 分钟前
RGW 对象多版本功能系统架构与代码解析
后端
Z思学30 分钟前
Nest 第一步 · 第 3 篇:理解 Controller / Service / Module 三层架构
后端
学长毕业设计32 分钟前
基于SpringBoot的校园爱心志愿管理系统(源码+文档+讲解视频)
vue.js·spring boot·后端
IT_陈寒1 小时前
SpringBoot自动配置失效?这个隐式依赖坑了我三天
前端·人工智能·后端
码视野1 小时前
基于 Spring Boot + Vue3 的【城市雨污水管网液位淤积溯源与立交桥下穿隧洞防汛排涝智控中台】设计与实现(含PRD/三端高保真源码/大屏)
java·前端·人工智能·spring boot·后端
小满zs1 小时前
Go语言第十章(指针)
后端·google·go
十正2 小时前
用 HTTP 条件请求把“强一致“和“低成本
网络·后端·http
2601_962122972 小时前
Spring Cloud——路由网关Zuul
后端·spring·spring cloud