第一次接触Borini是在一个自动化测试项目里。同事扔过来一个配置文件说“用这个跑”。当时没当回事,结果半小时后卡在环境变量上。Borini的文档不算差,新手容易掉进一个坑,把它当成普通脚本工具的,直接复制示例命令,忽略掉依赖版本。

我试过在Ubuntu 22.04上跑Borini 2.3,Python 3.9以下直接报错了,提示importlib.metadata缺失的。换到3.10立刻正常,所以第一步别急着写任务。先确认Python版本和系统架构是这个细节官方快速开始里只在一行小字里提过。配置Borini的核心是borini.yaml,别被这个名字骗了,它支持JSON和TOML了。我习惯用YAML,因为注释方便的。一个常见错误是把任务间的依赖写成列表嵌套列表,实际应该用扁平字符串加冒号分隔的。

build:test 表示test依赖build。上周帮一个团队排查,他们的CI流水线每次到deploy就挂,查了半天发现依赖写成了 - build - test,Borini解析时把test当成了独立任务,顺序全乱。改掉之后,部署时间平均4分钟降还有1分半。Borini的任务调度是拓扑排序,写错依赖不会报错。只会静默乱序是这点挺坑的。插件系统是Borini真正拉开差距的地方。官方仓库里有三十多个插件,常用的就五六个,shell、http、file、docker、slack了。我一般只装shell和http。

其他用自定义脚本替代了。原因很简单。插件多了启动慢,但且版本冲突概率翻倍。

有个做数据管道的朋友非要用Borini的sql插件,结果跟psycopg2的版本锁死,折腾两天了。换成shell调用psql,十行代码搞定。Borini的插件机制设计得灵活,灵活不等于该滥用。我的经验是能用原生shell解决的就别引入插件,除非需要跨平台或者复杂重试逻辑。实际跑起来之后,监控和日志是第二个容易翻车的地方。Borini默认把日志写到~/.borini/logs/,按任务名分文件,不自动轮转。跑一周就能攒出几个G吧?我现在的做法是在borini.yaml里加一个全局钩子,每次任务结束调一下logrotate,另外Borini有个隐藏功能。

设置环境变量BORINI_TRACE=1会输出每个任务的用的时间和返回值,调试时非常有用,文档里没写。这个是我翻源码发现的,issue里有人提过,一直没合并到文档。用上之后,定位慢任务从靠猜变成看表格,效率差太多了。,最后说个反直觉的点。

Borini不适合做实时性要求高的调度。它的最小时间粒度是秒级,实际触发有几十到几百毫秒的抖动吧?我试过用它做行情采集,每5秒一次,结果时间戳偏差最大到过1.2秒。老老实实换回crontab加锁的。Borini的强项是任务编排和错误重试,一个任务失败后自动触发补偿流程,或者根据HTTP状态码决定是否重跑呢?把它用在批处理、CI/CD、数据管道场景,稳定得很。选工具跟选鞋一样,合脚最重要,不要硬塞。