You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派断电时修改文本文件:Node.js监听SIGPWR信号失效问题

树莓派断电时Node.js未捕获SIGPWR并写入日志的问题分析与解决

问题根源

你遇到的核心问题在于树莓派断电时系统的瞬间崩溃特性,导致两个关键环节失效:

  1. 信号传递不及时:当树莓派直接拔掉电源,硬件层面的电源丢失会让系统瞬间停止运行,内核可能来不及将SIGPWR信号发送给Node.js进程,进程根本没机会执行信号回调。
  2. 文件写入未持久化:即使进程收到了信号,fs.appendFileSync虽然是同步写入,但操作系统通常会对磁盘写操作做缓存优化——数据先存在内存缓存里,再批量刷到硬盘。断电瞬间缓存里的数据还没来得及写入物理磁盘,日志自然留不下。

可行的解决办法

1. 强制刷写文件缓存到磁盘

修改你的信号回调,在写入日志后立即调用fs.fsyncSync强制将缓存数据刷到硬盘,确保写入操作真正完成:

var fs = require('fs');
var path = '/home/pi/Documents/Code/surveillanceCam/log/logfile.txt';
const logFileHandle = fs.openSync(path, 'a'); // 打开持久化文件句柄

fs.writeFileSync(path, new Date().toString() + ': Start\n');
fs.fsyncSync(logFileHandle); // 启动日志也强制刷写

process.on('exit', function () {
  fs.appendFileSync(path, new Date().toString() + ': exit\n');
  fs.fsyncSync(logFileHandle);
});
process.on('SIGPWR', function () {
  fs.appendFileSync(path, new Date().toString() + ': SIGPWR\n');
  fs.fsyncSync(logFileHandle);
  process.exit(0); // 主动触发exit事件,确保后续清理逻辑执行
});
process.on('SIGINT', function () {
  fs.appendFileSync(path, new Date().toString() + ': SIGINT (Ctrl+C)\n');
  fs.fsyncSync(logFileHandle);
  process.exit(0);
});
process.stdin.resume();

2. 配置系统层面的断电信号触发

有些树莓派发行版默认没有启用SIGPWR的触发机制,你可以检查并配置:

  • 确认系统是否加载了电源检测相关的内核模块,比如rpi_power_monitor
  • 编辑/etc/systemd/system.conf,将DefaultTimeoutStopSec设置为10s左右,给进程足够的处理时间

3. 硬件层面的兜底方案(最可靠)

依赖系统信号本质上受限于系统的存活时间,最稳妥的方式是通过GPIO检测电源状态:

  • 给树莓派外接一个简单的电压检测模块,监控电源输入电压
  • 当检测到电压低于阈值(比如4.8V)时,立即触发日志写入和刷写操作
  • 这种方式不依赖系统内核,能在系统崩溃前更早地捕获断电事件

4. 搭配小型UPS(不间断电源)

如果条件允许,给树莓派配一个迷你UPS(比如基于18650电池的模块),断电后能提供3-5秒的供电时间,足够系统完成信号传递、日志写入和刷写的全流程。

针对你的后续需求的优化

对于启动时检查非正常关机的逻辑,可以在服务启动时读取日志文件的最后几行:

function checkUncleanShutdown() {
  try {
    const logContent = fs.readFileSync(path, 'utf8');
    const lines = logContent.trim().split('\n');
    const lastLine = lines[lines.length - 1];
    // 判断最后一条记录是否是启动记录,且没有后续的结束标记
    if (lastLine.includes(': Start') && lines.length === 1) {
      console.error('检测到非正常关机!');
      // 这里可以添加报错逻辑,比如发送通知、记录异常日志等
    }
  } catch (err) {
    // 日志文件不存在,视为首次启动
    console.log('首次启动,创建日志文件');
    fs.writeFileSync(path, new Date().toString() + ': Start\n');
    fs.fsyncSync(logFileHandle);
  }
}
// 启动时先执行检查逻辑
checkUncleanShutdown();

内容的提问来源于stack exchange,提问作者Addeuz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:31:10