为什么做完这个项目以后,我会越来越在意日志、异常处理和权限
这篇还是接在 vchoo 这条线后面写。
前面几篇已经把故事生成、分镜拆分、生图任务调度、超时和降级这些主链路拆开了。那段时间我最大的变化,不只在“把 AI 能力接进业务”这件事上。项目越往后做,我越能感觉到,系统能不能长期跑下去,很多时候要看的反而是几件很基础、平时又很容易被嫌麻烦的东西:日志、异常处理和权限。
1. 一开始做项目时,最容易把注意力都放在“功能通没通”上
刚开始接 vchoo 这类项目时,人的注意力很自然会落在主链路上。
比如:
- 故事能不能生成
- 分镜能不能拆出来
- 生图能不能跑
- 任务状态能不能查
因为这些东西最直观,也最容易被看到。
前端点一下,页面一转,接口一回,大家先看的都是这些。
那时候我对很多基础能力的理解还偏“辅助项”。
会觉得:
- 日志先打一点就行
- 异常先 catch 住别炸掉就行
- 权限后面再慢慢补
这种想法在项目前期很常见,短时间内看起来也不是完全跑不动。
但 vchoo 这种链路一旦开始变长,调用层一多、任务一多、状态一多,问题就会集中冒出来。那个时候我才真正体会到,很多东西前面不补,后面会连本带利地还回来。
2. 我最先开始在意日志,是因为很多问题光靠“现象”根本定位不动
做普通小功能的时候,有些问题其实挺直给的。
- 页面没显示
- 接口报错
- 参数传错
这类问题顺着报错点往回找,很多时候还能查得动。
但 vchoo 这条链不一样。
它中间隔着很多层:
- 用户输入
- LLM 生成故事
- 分镜拆分
- 生图任务下发
- ComfyUI 执行
- 回调回流
- 状态更新
到了这个阶段,很多问题给到你时,表面现象会非常弱。
比如:
- 用户说“这次卡住了”
- 前端看到任务一直在执行中
- 某个分镜最后没出图
- 某次重试之后结果不对
这些问题如果没有日志,后端视角其实非常被动。
因为你根本不知道问题到底卡在哪一段:
- 是故事生成慢了
- 还是分镜拆分结构有问题
- 是任务根本没下发出去
- 还是 ComfyUI 已经执行了,但结果没回写
- 是回调迟到
- 还是状态更新被后面的逻辑覆盖了
到这个阶段,日志不再只是“记一记发生了什么”,而是:
系统出了问题以后,你还有没有能力把它倒着推回去。
这个价值我是在真实链路里被教育出来的。
3. 后来我对日志的理解,慢慢从“打印调试信息”变成了“保留链路证据”
刚开始写代码时,打日志很容易带着一种临时感。
比如:
- 到这里了,打印一下
- 这个变量值是什么,打印一下
- 这个接口有没有进来,打印一下
这种日志在本地调试时当然有用,但放到业务系统里,很快就不够了。
因为真要查问题的时候,光有一两行零散信息根本不够,你需要的是一条能串起来的过程证据。
所以我后来会更在意日志里到底有没有这些东西:
- 当前是哪一次创作任务
- 当前是哪一个分镜
- 当前在哪个阶段
- 输入参数大概是什么
- 外部调用结果是什么
- 状态从什么变成了什么
- 失败发生在什么时候
这些信息一旦能留住,很多问题就开始能被顺着看了。
我后来对日志的感觉越来越像:
它比“随手打印出来的附属输出”重要得多,更像是系统留给自己的一条时间线。
这条时间线在平时可能没什么存在感,但一出问题,它就是最值钱的东西。
4. 异常处理这件事,我后来越来越在意,是因为“报错”并不是最可怕的状态
这点在 AI 业务里尤其明显。
一开始很容易把异常处理理解成:
- 别让接口 500
- 报错了就 catch
- 给前端返回一句失败
但项目做深一点以后,我更在意的反而是另外几种状态:
- 没报错,但结果不可用
- 失败了,但状态没改
- 某一层吞掉了异常,后面继续往下跑
- 前端看到的是成功,系统内部其实已经半失败
这种情况比直接抛异常更难受。
因为直接报错至少还算明确,系统会立刻提醒你出了问题。
最麻烦的是那种:
- 没完全成功
- 也没完全失败
- 状态挂在中间
- 用户还以为可以继续等
前面写任务调度、超时、降级的时候,其实已经碰到不少这种问题了。
所以我后来对异常处理的要求也开始变高。
我不再只满足于“捕获住别炸”,而是会更关注:
- 失败以后状态有没有明确落下来
- 前端拿到的是不是可解释的结果
- 这次失败会不会影响后续链路
- 以后如果重试,系统能不能接得住
这个时候,异常处理已经直接影响业务行为了,不再只是代码卫生问题。
5. 到这个阶段,我开始能体会到“统一异常处理”为什么重要
如果异常只是散在每个接口、每个服务方法里零零碎碎地处理,短时间看着也能跑。
但项目一多以后,很快就会出几个问题:
- 每个接口返回风格不一样
- 有的地方抛异常,有的地方吞掉
- 有的地方写日志,有的地方什么都不记
- 同一种失败,在不同位置会被处理成不同结果
这对前后端和后续维护都很不友好。
因为它意味着:
- 前端很难统一处理
- 后端很难统一排查
- 运维和测试也很难快速判断问题严重度
所以我后来会越来越认可统一异常处理这件事。
它的意义在我看来主要有三点:
第一,统一收口
不管底层哪里出问题,至少最后给出去的结果风格要一致。
第二,统一留痕
异常信息、上下文、任务标识这些东西,最好能有固定方式被记下来。
第三,统一状态转换
失败以后系统到底该标什么状态、返回什么结果,不要每个地方自己发挥。
这个思路一旦有了,项目整体会稳很多。
6. 权限这件事,我一开始确实有点低估了,觉得后台先能用再说
只看功能推进节奏,权限往往不是最先被盯上的点。
尤其是做内部后台时,很容易默认:
- 都是内部人在用
- 功能先跑起来更重要
- 后面再细化角色和权限也来得及
我当时也有过这种心态。
但随着后台功能一点点变多,这个问题很快就开始冒头。
因为后台一旦开始管理:
- 素材
- 活动配置
- 状态切换
- 任务结果
- 运营开关
这些东西其实已经不是“看一眼数据”那么简单了。
很多操作都在直接影响线上展示和业务结果。
这时候你就不能只问“这个功能做没做”,还得问:
- 谁能看
- 谁能改
- 谁能发起关键动作
- 谁能改状态
- 谁能重试、取消或者重新发布
权限这件事一旦不清楚,后面很容易出现两种问题:
第一,越权太宽
谁都能碰关键配置,风险很大。
第二,边界太糊
某个动作到底算运营操作、管理操作,还是开发辅助操作,说不清楚。
我后来对权限越来越在意,就是因为我开始意识到:
后台系统真正危险的地方,很多时候不在“能看到什么”,而在“能改动什么”。
7. 做完这个项目后,我对权限的理解也从“页面访问控制”走到了“动作控制”
刚开始接触权限时,最容易想到的是页面级别:
- 这个菜单能不能看到
- 这个页面能不能进
这些当然重要,但往后做一点,很快就会发现它不够。
因为很多真正关键的风险点,都落在动作上,很少落在页面本身。
比如:
- 能不能切活动状态
- 能不能替换素材
- 能不能删除配置
- 能不能重试任务
- 能不能查看某些敏感记录
这些动作如果不单独收住,就算页面入口拦住了,也不一定真的安全。
所以我后来会更在意:
- 菜单权限是一层
- 接口权限是一层
- 数据权限是一层
- 关键动作权限又是一层
这个理解一出来,我对权限这件事的态度就完全不一样了。
它不再只是“后台常规配置项”,而是系统边界的一部分。
8. 回头看,日志、异常处理、权限这三件事,其实都在回答同一个问题:系统失控时,你能不能把它拉回来
这可能是我做完 vchoo 这一段以后,感受最深的一点。
表面上看,这三件事属于完全不同的主题:
- 日志偏排查
- 异常处理偏稳定性
- 权限偏安全和边界
但放到真实项目里,它们其实在回答一个共同的问题:
系统开始复杂之后,一旦事情没按预期走,你还有没有办法把局面收回来。
日志解决的是:
- 你还看不看得见发生了什么
异常处理解决的是:
- 失败以后状态会不会继续扩散
权限解决的是:
- 哪些动作本来就不该被随便触发
这三层一旦都没有,系统表面上功能再全,后面也会非常脆。
9. 所以这段经历带给我最大的变化,是我开始知道“长期维护”靠什么支撑
只看功能清单,vchoo 这一段当然能列出很多东西:
- 故事生成
- 分镜拆分
- 生图调度
- 重试取消
- 超时降级
这些都是真的,也确实重要。
但我现在回头看,更影响我后面做事方式的,其实是另一层:
我开始知道,一个系统能不能长期维护,关键得看底下这些基础能力有没有慢慢补齐,而不是功能点堆得多快。
因为业务一变、任务一多、状态一复杂,最后最先救命的,往往不是你又多会了一个接口,更多是下面这些基础能力:
- 日志能不能追
- 异常能不能收
- 权限边界清不清楚
这个认识对我来说挺重要。
它让我后面再做东西时,会自然多问几句:
- 这一步失败了以后系统怎么办
- 这个动作有没有必要留操作痕迹
- 这个接口谁都能调吗
- 以后查问题时,我能不能把链路倒回来
这些问题以前我不太会主动问,现在会了。
10. 这篇先记一个阶段结论
做完 vchoo 这段以后,我现在先给自己记几个比较明确的结论:
- 功能链越复杂,日志就越像系统的回放能力
- 异常处理不能只停在 catch 住别炸,还要关心状态有没有收住
- 统一异常处理的价值,在于统一结果、统一留痕、统一收口
- 权限控制真正关键的地方,更多在关键动作和接口边界,不只在页面入口
- 日志、异常处理、权限这些基础能力,决定的是系统能不能长期维护,也决定它是不是只能勉强跑通
这篇先写到这里。
