本文目录导读:

我来介绍几种常见的进程守护脚本写法,适用于不同场景。
Shell 脚本守护(Linux/Unix)
基础守护脚本
#!/bin/bash
# 进程守护脚本
PROCESS_NAME="your_app"
PROCESS_PATH="/usr/local/bin/your_app"
LOG_FILE="/var/log/process_monitor.log"
while true; do
# 检查进程是否在运行
if ! pgrep -f "$PROCESS_NAME" > /dev/null; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - $PROCESS_NAME 未运行,正在重启..." >> $LOG_FILE
# 启动进程
$PROCESS_PATH >> $LOG_FILE 2>&1 &
echo "$(date '+%Y-%m-%d %H:%M:%S') - $PROCESS_NAME 已重启" >> $LOG_FILE
fi
# 每10秒检查一次
sleep 10
done
带PID文件的守护脚本
#!/bin/bash
# 定义进程信息
APP_NAME="myapp"
APP_PATH="/opt/myapp/myapp.sh"
PID_FILE="/var/run/${APP_NAME}.pid"
LOG_FILE="/var/log/${APP_NAME}_monitor.log"
start_app() {
nohup $APP_PATH > /dev/null 2>&1 &
echo $! > $PID_FILE
echo "$(date '+%Y-%m-%d %H:%M:%S') - PID: $! 已启动" >> $LOG_FILE
}
stop_app() {
if [ -f $PID_FILE ]; then
pid=$(cat $PID_FILE)
kill -9 $pid 2>/dev/null
rm -f $PID_FILE
echo "$(date '+%Y-%m-%d %H:%M:%S') - 已停止" >> $LOG_FILE
fi
}
check_app() {
if [ -f $PID_FILE ]; then
pid=$(cat $PID_FILE)
if kill -0 $pid 2>/dev/null; then
return 0 # 运行中
else
rm -f $PID_FILE
return 1 # 未运行
fi
else
return 1
fi
}
# 主循环
while true; do
if ! check_app; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - 检测到进程未运行,重启中..." >> $LOG_FILE
start_app
fi
sleep 30
done
Python 守护脚本
简单版
#!/usr/bin/env python3
import subprocess
import time
import sys
import logging
logging.basicConfig(
filename='/var/log/app_monitor.log',
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
PROCESS_CMD = ["python", "my_app.py"] # 要守护的进程命令
def check_process(proc):
"""检查进程是否存活"""
return proc.poll() is None
def start_process():
"""启动新进程"""
proc = subprocess.Popen(
PROCESS_CMD,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True
)
logging.info(f"进程启动,PID: {proc.pid}")
return proc
def main():
# 启动初始进程
proc = start_process()
while True:
if not check_process(proc):
logging.warning(f"PID {proc.pid} 已退出,退出码: {proc.returncode}")
proc = start_process()
# 每5秒检查一次
time.sleep(5)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n监控脚本被终止")
sys.exit(0)
高级版(带负载均衡和重启限制)
#!/usr/bin/env python3
import subprocess
import time
import logging
import signal
import sys
from datetime import datetime, timedelta
class ProcessGuard:
def __init__(self, command, check_interval=5, max_restarts=10, window=300):
self.command = command
self.check_interval = check_interval
self.max_restarts = max_restarts
self.window = window
self.process = None
self.restart_history = []
logging.basicConfig(
filename='process_guard.log',
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
signal.signal(signal.SIGINT, self.signal_handler)
signal.signal(signal.SIGTERM, self.signal_handler)
def signal_handler(self, sig, frame):
"""处理退出信号"""
logging.info(f"收到信号 {sig},停止守护进程")
if self.process:
self.process.terminate()
sys.exit(0)
def can_restart(self):
"""检查是否超过重启限制"""
if not self.restart_history:
return True
# 清理过期记录
now = time.time()
self.restart_history = [t for t in self.restart_history
if now - t < self.window]
return len(self.restart_history) < self.max_restarts
def start_process(self):
"""启动受保护进程"""
try:
self.process = subprocess.Popen(
self.command,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT
)
logging.info(f"进程启动,PID: {self.process.pid}")
return True
except Exception as e:
logging.error(f"进程启动失败: {e}")
return False
def monitor(self):
"""监控进程"""
if not self.start_process():
logging.error("初始进程启动失败")
return
while True:
time.sleep(self.check_interval)
if self.process.poll() is not None:
if self.can_restart():
self.restart_history.append(time.time())
logging.warning(f"进程异常退出(退出码: {self.process.returncode}),正在重启...")
self.start_process()
else:
logging.error("重启次数过多,暂停重启")
break
# 使用示例
if __name__ == "__main__":
guard = ProcessGuard(
command="python my_app.py",
check_interval=10,
max_restarts=5,
window=300
)
guard.monitor()
Systemd 服务守护(推荐生产环境)
创建 /etc/systemd/system/myapp.service:
[Unit] Description=My Application Service After=network.target [Service] Type=simple User=your_user WorkingDirectory=/path/to/app ExecStart=/usr/bin/python3 /path/to/app/my_app.py Restart=always RestartSec=10 # 每次重启前等待时间 # 优雅停止 TimeoutStopSec=30 KillSignal=SIGTERM # 资源限制 MemoryMax=1G CPUQuota=50% [Install] WantedBy=multi-user.target
启用服务:
sudo systemctl daemon-reload sudo systemctl enable myapp.service sudo systemctl start myapp.service # 查看状态 sudo systemctl status myapp.service
Docker/容器守护
Docker Compose 文件
version: '3.8'
services:
myapp:
image: myapp:latest
restart: always # 容器退出时自动重启
environment:
- TZ=Asia/Shanghai
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 60s
timeout: 5s
retries: 3
start_period: 30s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
选择建议
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 生产环境 | Systemd | 原生支持、可靠、配置灵活 |
| Linux 简单任务 | Shell 脚本 | 轻量、易修改 |
| 复杂逻辑 | Python 脚本 | 可编程、可扩展 |
| 容器环境 | Docker restart | 简单、容器生态支持 |
| 分布式系统 | Kubernetes | 自动扩缩容、自愈 |
最佳实践建议:
- 日志管理:保留进程日志,方便排查
- 优雅停止:支持 SIGTERM,让进程有时间保存状态
- 启动限制:防止进程崩溃循环重启
- 监控告警:重启次数过多时发送告警
- 资源限制:防止进程占用过多内存/CPU
- 健康检查:不只是检查进程存活,还要检查业务健康
根据你的具体需求选择合适的方案即可。