Python 环境变量设为 false 仍启用:布尔开关的定位与入口校验
适用场景与现象 一个批处理服务用 EXPORT_ENABLED 控制是否生成导出文件。发布配置里已经写了 false,应用重启后却仍进入导出分支。开发环境不设置该变量时,功能又能正常关闭。 下面用这个场景复现问题。它适用于直接读取环境变量的 Python 程序;如果项目使用配置框架,应先查明框架自己的布尔解析规则,避免
技术笔记、项目复盘、阅读摘录和问题清单。
适用场景与现象 一个批处理服务用 EXPORT_ENABLED 控制是否生成导出文件。发布配置里已经写了 false,应用重启后却仍进入导出分支。开发环境不设置该变量时,功能又能正常关闭。 下面用这个场景复现问题。它适用于直接读取环境变量的 Python 程序;如果项目使用配置框架,应先查明框架自己的布尔解析规则,避免
接口返回成功,主表记录也还在,但关联明细突然清空。遇到这种现象,先找到实际执行的 SQL:如果所谓“更新”用了 INSERT OR REPLACE,就要沿着删除路径排查。 本文用一个订单与明细模型复现问题,再把写入改成有明确冲突目标的 UPSERT。实验只使用内存数据库,不连接生产服务。 适用场景与现象 适用于 SQL
适用场景与异常表现 离线任务跑了 26 小时,报表却显示只耗时 2 小时;开始、结束时间颠倒了 1 秒,监控却出现接近 24 小时的长任务;耗时 250 毫秒的接口被统计为 0 秒。这三种现象可能来自同一行代码: duration_seconds = (finished_at - started_at).seconds
适用场景:地址跳转成功,业务请求却变了 接口从 /orders 迁移到 /orders/,或者网关增加域名规范化规则后,调用方开始收到 405、参数缺失,甚至收到 200 的 HTML 页面。调用日志只保留最终响应,看起来像后端突然不认识请求体。 这类问题先查重定向链:客户端发出的第一跳是 POST,不代表最终到达业务
配置导入接口返回成功,回读结果却与提交内容不一致。先检查客户端发出的原始 JSON:同一个对象里可能出现了两次 quota,而解析器只留下了后一个值。等数据变成字典,再严格的字段校验也找不回被覆盖的那一项。 本文以“批量任务额度配置”为例,把排查推进到解析入口,并提供可以独立运行的实现与回归测试。示例使用 Python
接口先查询计数器,再更新它。连接已经设置 timeout=5,更新却几乎立即返回 database is locked。把超时调到 30 秒仍然失败,而同一条 SQL 在新连接上可以成功。此时要检查失败连接是否持有旧的读快照。 本文针对 Python 3.12+ 标准库 sqlite3、本机文件数据库、WAL 模式和独
服务还在使用 Python 3.13,开发机已经安装 3.14,3.15 又发布了。真正需要判断的是:哪些功能能解决项目里的问题,哪些行为变化会让原来的代码失败,以及如何验证升级没有改变业务结果。 本文以 2026 年 10 月 17 日为时间点,比较三个版本的主要变化。Python 3.13 于 2024 年 10
订单明细表已经写了 REFERENCES orders(id),导入程序却能插入不存在的订单号。更容易误判的情况是:初始化脚本设置过 PRAGMA foreign_keys = ON,接口仍然产生孤儿明细。 这时先确认写入连接的状态。SQLite 的外键执行开关属于连接;迁移连接开启,不代表接口、后台任务和临时导入脚本
一个报表接口连续执行两次:第一次查询订单,第二次查询库存。库存请求却带上了订单请求追加的字段。重启进程后暂时恢复,压测时又复现。数据库查询本身没有问题,污染发生在构造查询参数之前。 这类故障不一定需要并发:同一进程中两个顺序调用就能触发。本文用纯 Python 标准库复现并修复,适用于长期运行的 Web 服务、任务 W
适用场景与现象 配置表按租户和作用域保存覆盖项:scope_id 有值表示某个具体作用域,为 NULL 表示租户默认配置。业务要求每个租户只能有一条默认配置,每个具体作用域也只能有一条。 表上已经有 UNIQUE (tenant_id, scope_id),压测后却出现两条默认配置。读取接口用 LIMIT 1 暂时掩盖