I
Member
线上出过一次事故,根因最后定位到一段 bare except:except: pass 把下游接口的超时异常吞了,任务显示成功、数据却没写进去,监控全绿、业务全错。从那以后我对异常处理定了几条规矩。
第一,永远不要写 bare except。至少写成 except Exception,并把异常对象打到日志里,带上关键上下文(任务 ID、入参摘要)。bare except 连 KeyboardInterrupt 和 SystemExit 都能吞,调试时想复现都复现不出来。
第二,区分可重试和不可重试。网络超时、连接重置可以重试;参数校验失败、鉴权失败重试一百次也没用。重试要加退避和上限,重试次数和间隔写进配置,别写死在代码里。
第三,异常链别断。Python 里用 raise ... from ... 保留原始异常,日志里能看到完整链路;直接 raise 新异常会把根因藏起来,接手的人只能靠猜。
第四,关键路径加兜底告警。except 块里除了记日志,对影响数据的异常要推一条告警,级别按影响面定。静默失败是最贵的故障,因为发现时间全靠用户投诉。
第五,finally 只放清理逻辑,别在 finally 里再抛异常或 return,会把原始异常覆盖掉,排查时看到的就不是第一现场。
这几条看着基础,但线上故障复盘里一半以上都能追溯到异常处理写得随意。你们有没有被 bare except 坑过的经历?当时是怎么定位到的?
第一,永远不要写 bare except。至少写成 except Exception,并把异常对象打到日志里,带上关键上下文(任务 ID、入参摘要)。bare except 连 KeyboardInterrupt 和 SystemExit 都能吞,调试时想复现都复现不出来。
第二,区分可重试和不可重试。网络超时、连接重置可以重试;参数校验失败、鉴权失败重试一百次也没用。重试要加退避和上限,重试次数和间隔写进配置,别写死在代码里。
第三,异常链别断。Python 里用 raise ... from ... 保留原始异常,日志里能看到完整链路;直接 raise 新异常会把根因藏起来,接手的人只能靠猜。
第四,关键路径加兜底告警。except 块里除了记日志,对影响数据的异常要推一条告警,级别按影响面定。静默失败是最贵的故障,因为发现时间全靠用户投诉。
第五,finally 只放清理逻辑,别在 finally 里再抛异常或 return,会把原始异常覆盖掉,排查时看到的就不是第一现场。
这几条看着基础,但线上故障复盘里一半以上都能追溯到异常处理写得随意。你们有没有被 bare except 坑过的经历?当时是怎么定位到的?