Linux下os.replace原子替换异常:Signal 15导致JSON日志损坏
问题原因及修复方案
核心原因
你的问题出在两个关键环节:
- 临时文件使用追加模式写入:代码里用
'a+'打开临时文件,这种模式不会覆盖已有内容,只会在末尾追加。如果之前某次操作因Signal 15中断,临时文件残留了未写完的不完整JSON(比如缺闭合括号),下次启动时新的完整JSON会直接追加到这个残缺文件后面,最终替换原日志后就出现了内容叠加的情况。 - Signal 15未被处理,写入过程被强制终止:Signal 15(SIGTERM)默认会直接终止进程,要是刚好赶上
json.dump正在写入临时文件,进程会立刻停掉,导致临时文件内容不完整。而你的代码没有提前清理临时文件,也没确保写入完成,残留的残缺文件就会被后续操作复用。
修复方法
1. 改用覆盖模式写入临时文件
把打开临时文件的模式从'a+'改成'w',这样每次都会重新创建/覆盖临时文件,彻底避免残留内容的影响:
with open(temp_file_name, 'w') as f: json.dump(existing, f, indent=2, default=vars)
2. 用唯一临时文件避免复用问题
推荐使用Python标准库的tempfile生成唯一临时文件,从根源上杜绝重复使用同一个临时文件的可能:
import tempfile import os # 在日志文件所在目录生成唯一临时文件,避免跨文件系统替换问题 with tempfile.NamedTemporaryFile(mode='w', delete=False, dir=os.path.dirname(log_file_path)) as tmp_file: json.dump(existing, tmp_file, indent=2, default=vars) # 原子替换原日志 os.replace(tmp_file.name, log_file_path) # 替换成功后清理临时文件,防止意外残留 os.unlink(tmp_file.name)
3. 处理Signal 15,保证写入完成
注册信号处理函数,让进程收到SIGTERM时先完成当前写入操作再退出,避免中途被强制终止:
import signal import sys def sigterm_handler(signum, frame): # 这里可以添加必要的收尾逻辑,确保当前写入操作完成 sys.exit(0) # 注册SIGTERM信号处理 signal.signal(signal.SIGTERM, sigterm_handler)
内容的提问来源于stack exchange,提问作者Sascha Lüthi
相关产品推荐
相关产品推荐

