with tempfile.NamedTemporaryFile('w', suffix='.csv', delete=True) as f:
    write_rows(f)
    f.flush()
    upload(f.name)

导出服务跑了两周,/tmp 里躺着 41 万个 tmp 开头的文件,加起来 37G。业务开始报 OSError: [Errno 28] No space left on device,连日志都写不进去。这类现象通常不是突然出现的,往前翻半天日志能看到苗头。

追下去是这么回事:每次请求都用 mkstemp 建临时文件,异常分支在 return 之前没有删,正常分支也只 unlink 了一半。Python 只有 TemporaryFile 会自己清理,mkstemp 返回路径和 fd,生命周期得自己管。

这次卡住的地方就在「tempfile 临时文件泄漏」这一环,单独把它拎出来验证,别和其他改动混在同一次发布里。权限不要一口气开到最大,先加到够用再往上试,范围小才好收。

把复现步骤压到三条以内,交给同事也能跑出来,才算真的定位清楚。改动写完就同步给同事,下一个人踩同一个坑,成本还是你的。

处理上按这个顺序:先用 find /tmp -name 'tmp*' -mtime +1 统计数量和占用;把建临时文件改成 with tempfile.TemporaryDirectory() 或 NamedTemporaryFile(delete=True);确实要保留路径的用 try/finally 包住 os.unlink;加一条定时清理 顺带盯 /tmp 的 inode 数。

确认没问题再收工,跑一天后 /tmp 文件数回到两位数 df 的 Use% 不再上涨 导出接口没有 28 报错。

作者 9823189