如何写一个进程守护脚本

wen 实用脚本 1

本文目录导读:

如何写一个进程守护脚本

  1. Shell 脚本守护(Linux/Unix)
  2. Python 守护脚本
  3. Systemd 服务守护(推荐生产环境)
  4. Docker/容器守护
  5. 选择建议

我来介绍几种常见的进程守护脚本写法,适用于不同场景。

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 自动扩缩容、自愈

最佳实践建议:

  1. 日志管理:保留进程日志,方便排查
  2. 优雅停止:支持 SIGTERM,让进程有时间保存状态
  3. 启动限制:防止进程崩溃循环重启
  4. 监控告警:重启次数过多时发送告警
  5. 资源限制:防止进程占用过多内存/CPU
  6. 健康检查:不只是检查进程存活,还要检查业务健康

根据你的具体需求选择合适的方案即可。

抱歉,评论功能暂时关闭!