让 OpenClaw 零崩溃、零断连、零漏执行。
场景危害🔴 半夜崩了凌晨 Gateway 挂掉,错过重要消息🔴 内存爆了运行一周后内存泄漏,被 OOM Kill🔴 网络断了Wi-Fi/运营商切换,TCP 连接断开🔴 任务丢了执行到一半崩溃,重启从头开始
方案崩溃后自启开机自启日志管理资源限制nohup❌❌❌ 需手动❌screen❌❌❌❌systemd✅✅✅ 内置✅ cgroupsPM2✅✅✅✅
✅ 用 systemd(Linux 推荐)或 PM2,不要用 nohup/screen。
创建服务文件 /etc/systemd/system/openclaw.service:
ini
[Unit]
Description=OpenClaw Gateway Service
Documentation=https://docs.openclaw.ai
After=network.target network-online.target
Wants=network-online.target
[Service]
Type=simple
User=openclaw
Group=openclaw
WorkingDirectory=/home/openclaw/.openclaw
ExecStart=/usr/local/bin/openclaw gateway start --no-daemon
Restart=always
RestartSec=10
LimitNOFILE=65535
MemoryMax=2G
TasksMax=4096
Environment="NODE_ENV=production"
EnvironmentFile=/home/openclaw/.openclaw/.env
StandardOutput=journal
StandardError=journal
SyslogIdentifier=openclaw
[Install]
WantedBy=multi-user.target
关键参数解释:
Restart=always — 任何异常退出都自动重启RestartSec=10 — 崩溃后等 10 秒再重启,避免频繁重启MemoryMax=2G — 内存超限后自动重启,防止 OOM启用服务:
bash
sudo systemctl daemon-reload
sudo systemctl enable openclaw
sudo systemctl start openclaw
sudo systemctl status openclaw
journalctl -u openclaw -f
bash
npm install -g pm2
pm2 start "openclaw gateway start --no-daemon" --name openclaw
pm2 save
pm2 startup
PM2 配置 ecosystem.config.js(见 scripts/ 目录):
js
module.exports = {
apps: [{
name: 'openclaw-gateway',
script: 'openclaw',
args: 'gateway start --no-daemon',
max_memory_restart: '1G', // 内存超 1G 自动重启
autorestart: true,
max_restarts: 10,
restart_delay: 10000,
node_args: '--expose-gc --max-old-space-size=2048',
}]
}
每 5 分钟检查一次 Gateway 是否存活,见 scripts/healthcheck.sh:
bash
# crontab -e
*/5 * * * * /home/openclaw/scripts/healthcheck.sh
脚本会自动:
/var/log/openclaw/healthcheck.logUptime Kuma(Docker 部署):
yaml
# docker-compose.yml
services:
uptime-kuma:
image: louislam/uptime-kuma:1
ports:
- "3001:3001"
restart: always
监控 http://localhost:9527/health,异常时推送通知到飞书/Telegram/Discord。
yaml
# 飞书配置
channels:
feishu:
reconnect:
enabled: true
maxRetries: 10
initialDelay: 1000 # 首次重连等待 1s
maxDelay: 60000 # 最大等待 60s
backoffMultiplier: 2 # 指数退避
# Discord 配置
channels:
discord:
gateway:
heartbeatInterval: 41250
reconnect:
enabled: true
maxRetries: -1 # 无限重试
js
async function callLLMWithRetry(prompt, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: prompt }]
});
} catch (error) {
if (error.status === 429) {
await sleep((error.headers?.['retry-after'] || 60) * 1000);
} else if (error.code === 'ECONNRESET' || error.code === 'ETIMEDOUT') {
await sleep(Math.pow(2, i) * 1000); // 指数退避
} else {
throw error;
}
}
}
throw new Error('Max retries exceeded');
}
text
任务开始 → 记录进度到文件/数据库
↓
任务执行中 → 定期更新进度
↓
崩溃重启 → 读取进度,从断点继续
js
const PROGRESS_FILE = '/home/openclaw/data/task_progress.json';
function saveProgress(taskId, progress) {
const data = JSON.parse(fs.readFileSync(PROGRESS_FILE, 'utf8') || '{}');
data[taskId] = { ...progress, updatedAt: Date.now() };
fs.writeFileSync(PROGRESS_FILE, JSON.stringify(data, null, 2));
}
function loadProgress(taskId) {
const data = JSON.parse(fs.readFileSync(PROGRESS_FILE, 'utf8') || '{}');
return data[taskId];
}
function clearProgress(taskId) {
const data = JSON.parse(fs.readFileSync(PROGRESS_FILE, 'utf8') || '{}');
delete data[taskId];
fs.writeFileSync(PROGRESS_FILE, JSON.stringify(data));
}
js
// ❌ 错误:依赖内存状态
let lastCheckTime = 0;
if (Date.now() - lastCheckTime > 3600000) { /* ... */ }
// ✅ 正确:持久化到文件
const stateFile = '/home/openclaw/data/heartbeat-state.json';
const state = JSON.parse(fs.readFileSync(stateFile, 'utf8'));
if (Date.now() - state.lastCheck > 3600000) {
state.lastCheck = Date.now();
fs.writeFileSync(stateFile, JSON.stringify(state));
}
js
await queue.add('sendNotification', {
channel: 'feishu', userId: 'ou_xxx', message: 'Task done!'
}, {
attempts: 3,
backoff: { type: 'exponential', delay: 2000 }
});
js
// ecosystem.config.js
{
max_memory_restart: '1G', // 超 1G 自动重启
}
js
const MB = 1024 * 1024;
setInterval(() => {
const usage = process.memoryUsage();
const heapUsed = usage.heapUsed / MB;
console.log(`Memory: ${heapUsed.toFixed(2)}MB`);
if (heapUsed > 1800) {
console.error('Memory limit exceeded, exiting...');
process.exit(1); // 让 systemd/PM2 重启
}
}, 60000);
启动时开启 GC: node --expose-gc your-app.js
bash
# 永久提高(/etc/security/limits.conf)
* soft nofile 65535
* hard nofile 65535
# systemd
LimitNOFILE=65535
bash
# cleanup.sh - 清理 7 天前日志
find /var/log/openclaw -name "*.log" -mtime +7 -delete
find /tmp/openclaw -type f -mtime +1 -delete
# crontab
0 3 * * * /home/openclaw/scripts/cleanup.sh
bash
# /etc/logrotate.d/openclaw
/var/log/openclaw/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 0640 openclaw openclaw
}
检查项命令预期结果服务状态systemctl status openclaw``active (running)开机自启systemctl is-enabled openclaw``enabled日志正常journalctl -u openclaw -n 50无 ERROR内存使用free -h有余量文件句柄ulimit -n≥ 65535健康检查curl localhost:9527/health``200 OK定时任务crontab -l有 healthcheck
没有 100% 稳定的系统,只有 100% 可恢复的系统。
保障层工具进程守护systemd / PM2异常重启healthcheck.sh + crontab断连重连渠道内置重连 + 指数退避断点续跑进度持久化到文件资源回收内存监控 + 自动重启日志追溯logrotate + journalctl
scripts/healthcheck.sh — 健康检查 + 自动重启scripts/cleanup.sh — 日志清理scripts/network_monitor.sh — 网络监控scripts/ecosystem.config.js — PM2 配置references/task-resume.md — 断点续跑详细文档