配置用 mv 原子替换,脚本返回成功,机器掉电重启后 /etc/app/conf 还是上一版。文件内容是旧的,新文件连影子都没有。第一次遇到会往复杂处想,其实漏掉的多是个小前提。
with open('/etc/app/.conf.new', 'w') as f:
f.write(text); f.flush(); os.fsync(f.fileno())
os.rename('/etc/app/.conf.new', '/etc/app/conf')
fd = os.open('/etc/app', os.O_DIRECTORY); os.fsync(fd); os.close(fd)
rename 改的是目录项,目录本身的元数据也要落盘才算完成。只对文件 fsync 不覆盖这一步,掉电后目录还指向旧 inode,新文件就成了孤儿。这一点先确认清楚,后面就不用反复试。
「目录 fsync 原子替换」这个问题文档写得含糊,实际行为以当前版本为准,别照旧版本的结论套。临时改动用注释写上日期和原因,过两周自己都记不清为什么这么写。
动手前把原文件复制一份带时间戳,出问题立刻换回去,比现场分析快得多。一次只改一处,改完立刻验证,几个改动叠在一起,出问题就说不清是谁导致的。
具体做法是,新内容写进同目录的临时文件并 fsync 该文件;rename 到目标名;打开目标目录 fsync 一次 把目录项刷下去;把这三步封装成函数 所有配置写入都走它。
改完照着核一遍,断电测试后 conf 内容是新的 临时文件没有残留。
