省心的邮件提醒监控进程
前言
在使用服务器运行重要的后台服务的时候,难免因为意外原因造成服务中断宕机。此时一个简单的监控进程就很有必要。监控进程脚本很简单,重点在配置邮件服务。
准备条件
本文中使用的是ubuntu22.04版系统。
正式开始
安装邮件服务
安装前先更新下系统
apt-get update
安装mailutils,出现图形选择界面直接默认下一步就行。
apt-get install -y mailutils
安装s-nail,如果出现图形选择界面也是直接默认下一步就行。
apt-get install -y s-nail
配置外部SMTP
安装好后,将如下几行加入/etc/s-nail.rc这个文件最下面。
vim /etc/s-nail.rc
将下面代码粘贴进去。
set from=569157865@163.com #设置发送邮箱
set smtp=smtps://smtp.163.com:465 #设置smtp服务器和端口
set smtp-auth-user=569157865@163.com #设置用户名
set smtp-auth-password=IHMRRQHMAXZECVUV #授权码,不是登录密码
set smtp-auth=login #认证方式
测试邮件发送
echo "卧槽!牛逼!可以可以!" |s-nail -s "整两句..." 951753852@qq.com
此时打开你的邮箱,查看是否收到邮件。
不出意外主题为”整两句…”,内容为”卧槽!牛逼!可以可以!”的邮件就发过来了。
SMTP配置补充说明
本文配置的发送邮件的邮箱是163平台的。如果是你配置的是同一平台并且使用的是同一端口,smtp服务器和端口就无需修改。另外保持服务465端口开放,用哪个开放哪个就行。下面详细说明。
set from=569157865@163.com
这个为发送邮箱,不需多说set smtp=smtps://smtp.163.com:465
- 163.com
接收邮件服务器:pop.163.com,端口:110或995(使用SSL时)
接收邮件服务器:imap.163.com,端口:143或993(使用SSL时)
发送邮件服务器:smtp.163.com,端口:25或465/994(使用SSL时) - 126邮箱
接收邮件服务器:pop.126.com,端口:110
发送邮件服务器:smtp.126.com,端口:25 - 139邮箱
POP3服务器地址:POP.139.com,端口:110
SMTP服务器地址:SMTP.139.com,端口:25 - QQ邮箱
接收邮件服务器:pop.qq.com,端口:110或995(使用SSL时)
接收邮件服务器:imap.qq.com,端口:143或993(使用SSL时)
发送邮件服务器:smtp.qq.com,端口:25或465/587(使用SSL时) - Gmail (google.com)
POP3服务器地址:pop.gmail.com,端口:995(使用SSL)
SMTP服务器地址:smtp.gmail.com,端口:587(使用SSL) - 雅虎邮箱
接收邮件服务器:pop.mail.yahoo.cn,端口:110或995(使用SSL时)
接收邮件服务器:imap.mail.yahoo.cn,端口:143或993(使用SSL时)
发送邮件服务器:smtp.mail.yahoo.cn,端口:25或465(使用SSL时) - HotMail
接收邮件服务器:pop3.live.com,端口:995
发送邮件服务器:smtp.live.com,端口:25
- 163.com
set smtp-auth-user=569157865@163.com
跟发送邮箱保持一致就行set smtp-auth-password=IHMRRQHMAXZECVUV
授权码,需要去到平台,如图:
set smtp-auth=login
此项为固定模式
发送邮件没问题的话,至此配置SMTP服务完成。可以进行下一步了。
监控脚本
在后台运行服务的同级目录新建一个MonitoringProcess.sh文件,名称随意。
touch MonitoringProcess.sh
然后将下面这段代码粘贴进去,保存退出。两种方式监测进程:(二选一)
- 进程的完整名称
- 进程ID
可根据自己的需要改良代码。比如监测多个进程等。
方式:1
ps -ef | grep 名称 #获取进程PID
ps -p 进程PID -o comm= #返回完整进程名称
以上两个指令可获取需要的参数。
#!/bin/bash
while true; do
#if pgrep 进程的完整名称 > /dev/null; then #进程完整名称
if ps -p 进程PID > /dev/null; then #进程PID
sleep 10 #每10秒查询一次。
else
current_time=$(TZ='Asia/Shanghai' date +"%Y-%m-%d %H:%M:%S")
echo "宕机时间:$current_time"|s-nail -s "微信的进程服务已宕机" 12345678@qq.com
# 一旦邮件发送,终止循环以防止不断发送邮件
break
fi
done
方式2
#!/bin/bash
# ==============================================================================
# AOMSERVER 守护进程脚本
# ==============================================================================
#
# 【功能说明】
# 1. 核心守护: 崩溃自动重启、被杀自动重启、僵尸进程自动清理重启。
# 2. 自动安装: 支持通过命令一键设置开机自启。
# 3. 日志管理: 内置日志轮转,防止磁盘写满。
# 4. 单例运行: 防止重复启动。
#
# 【使用说明】
# 1. 启动服务: ./aomserver.sh
# 2. 设置开机自启: ./aomserver.sh --install <-- 新增功能
# 3. 取消开机自启: ./aomserver.sh --uninstall <-- 新增功能
# 4. 停止服务: pkill -f aomserver.sh
# 5. 查看状态: ./aomserver.sh --status
# 6. 查看日志: tail -f /tmp/aomserver.log
#
# ==============================================================================
# ------------------------------------------------------------------------------
# >>> [配置区域] 请根据您的实际情况修改以下 3 项 <<<
# ------------------------------------------------------------------------------
# [1] 你的真实启动命令 (必须是绝对路径)
# 注意: Crontab 启动时环境变量可能为空,请务必使用绝对路径 (如 /usr/bin/python3)
REAL_COMMAND="/usr/bin/python3 /opt/aom/main.py"
# [2] 进程唯一关键字
# 脚本通过 "ps -ef | grep 关键字" 判断服务是否存活
# 请确保足够独特,例如脚本名 "main.py" 或 jar包名 "app.jar"
PROCESS_KEY="main.py"
# [3] 日志文件路径
# 建议: root用户用 /var/log/aomserver.log,普通用户用 /tmp/aomserver.log
LOG_FILE="/tmp/aomserver.log"
# ------------------------------------------------------------------------------
# >>> 系统内部变量 <<<
# ------------------------------------------------------------------------------
DAEMON_NAME="aomserver.sh" # 脚本名称
CHECK_INTERVAL=3 # 检测周期(秒)
MAX_LOG_SIZE=10485760 # 日志最大限制 10MB
PID_FILE="/tmp/aomserver.service.pid" # 业务PID
DAEMON_PID_FILE="/tmp/aomserver.daemon.pid" # 守护PID
# 获取当前脚本的绝对路径 (用于开机自启配置)
CURRENT_SCRIPT_PATH=$(readlink -f "$0")
# ==============================================================================
# 核心工具函数
# ==============================================================================
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}
# 帮助菜单
show_help() {
echo "用法: $0 [选项]"
echo ""
echo "选项:"
echo " (无参数) 启动守护进程"
echo " --install 安装开机自启 (添加到 Crontab)"
echo " --uninstall 移除开机自启"
echo " --status 查看运行状态"
echo " --help 显示帮助"
echo ""
echo "日志位置: $LOG_FILE"
}
# --- 新增: 自动安装开机自启 ---
install_autostart() {
echo "正在设置开机自启..."
# 1. 检查是否已经安装过
if crontab -l 2>/dev/null | grep -Fq "$CURRENT_SCRIPT_PATH"; then
echo "⚠️ 警告: 开机自启已存在,无需重复安装。"
exit 0
fi
# 2. 写入 Crontab (@reboot 任务)
# 使用临时文件避免破坏现有的 cron 任务
(crontab -l 2>/dev/null; echo "@reboot $CURRENT_SCRIPT_PATH") | crontab -
if [ $? -eq 0 ]; then
echo "✅ 成功! 已将脚本路径加入 Crontab: $CURRENT_SCRIPT_PATH"
echo " 下次重启服务器时,此服务将自动启动。"
else
echo "❌ 失败! 无法修改 Crontab,请检查当前用户权限。"
fi
}
# --- 新增: 移除开机自启 ---
uninstall_autostart() {
echo "正在移除开机自启..."
# 1. 过滤掉包含当前脚本路径的行,重新写入 crontab
crontab -l 2>/dev/null | grep -Fv "$CURRENT_SCRIPT_PATH" | crontab -
echo "✅ 已移除相关启动项。"
}
# 日志轮转 (Copy-Truncate)
rotate_log_if_needed() {
if [ -f "$LOG_FILE" ] && [ "$(stat -c%s "$LOG_FILE")" -gt $MAX_LOG_SIZE ]; then
log "🔄 日志文件过大,执行轮转..."
cp "$LOG_FILE" "$LOG_FILE.$(date +%F_%H%M%S)"
echo "" > "$LOG_FILE"
fi
}
# 精准存活检测
is_service_running() {
# 策略A: 检查 PID 文件
if [ -f "$PID_FILE" ]; then
PID=$(cat "$PID_FILE")
if ps -p "$PID" > /dev/null 2>&1; then
STATE=$(ps -p "$PID" -o stat= | cut -c 1)
# 排除 Z (Zombie) 和 T (Stopped)
if [ "$STATE" != "Z" ] && [ "$STATE" != "T" ]; then
# 二次校验: 命令行是否包含关键字
if ps -p "$PID" -o args= | grep -q "$PROCESS_KEY"; then
return 0
fi
fi
fi
fi
# 策略B: 进程表扫描 (排除 grep, 排除守护进程自身, 排除僵尸进程)
COUNT=$(ps -ef | grep "$PROCESS_KEY" | grep -v "grep" | grep -v "$DAEMON_NAME" | grep -v "defunct" | wc -l)
if [ "$COUNT" -gt 0 ]; then
# 补写 PID 文件
pgrep -f "$PROCESS_KEY" | head -n 1 > "$PID_FILE"
return 0
fi
return 1
}
start_service() {
log "🚀 启动服务: $REAL_COMMAND"
nohup $REAL_COMMAND >> "$LOG_FILE" 2>&1 &
echo $! > "$PID_FILE"
sleep 1
}
stop_service_gracefully() {
if [ -f "$PID_FILE" ]; then
PID=$(cat "$PID_FILE")
if kill -0 "$PID" 2>/dev/null; then
log "🛑 正在停止业务进程 (PID=$PID)..."
kill "$PID"
for i in {1..5}; do kill -0 "$PID" 2>/dev/null || break; sleep 1; done
kill -9 "$PID" 2>/dev/null
fi
rm -f "$PID_FILE"
else
pkill -f "$PROCESS_KEY"
fi
}
# ==============================================================================
# 主逻辑控制
# ==============================================================================
# 确保脚本可执行
chmod +x "$0"
case "$1" in
--help)
show_help
exit 0
;;
--install)
install_autostart
exit 0
;;
--uninstall)
uninstall_autostart
exit 0
;;
--status)
if pgrep -f "$DAEMON_NAME" | grep -v $$ > /dev/null; then
echo "✅ 守护进程正在运行."
echo " 守护进程 PID: $(cat $DAEMON_PID_FILE 2>/dev/null)"
echo " 服务运行状态: $(is_service_running && echo '运行中' || echo '未运行')"
else
echo "❌ 守护进程未运行."
fi
exit 0
;;
--daemon-mode)
# 内部模式,请勿手动调用
;;
*)
# 默认启动检查
if [ -f "$DAEMON_PID_FILE" ]; then
OLD_PID=$(cat "$DAEMON_PID_FILE")
if ps -p "$OLD_PID" > /dev/null 2>&1 && ps -p "$OLD_PID" -o args= | grep -q "$DAEMON_NAME"; then
echo "❌ 错误: AOMServer 守护进程已在运行 (PID=$OLD_PID)"
echo "💡 提示: 停止命令: pkill -f $DAEMON_NAME"
exit 1
fi
fi
echo "✅ 正在启动守护进程..."
nohup "$0" --daemon-mode >> "$LOG_FILE" 2>&1 &
echo "✅ 启动成功! 日志文件: $LOG_FILE"
exit 0
;;
esac
# ==============================================================================
# 守护进程后台循环 (仅后台模式运行)
# ==============================================================================
echo $$ > "$DAEMON_PID_FILE"
log ">>> 守护进程初始化 (Monitor PID: $$)"
# 信号捕获 (清理逻辑)
trap 'log "📴 收到停止信号,退出。"; stop_service_gracefully; rm -f "$DAEMON_PID_FILE"; exit 0' SIGTERM SIGINT
while true; do
rotate_log_if_needed
if ! is_service_running; then
log "⚠️ 检测到服务异常,准备重启..."
start_service
log "✅ 服务已重新拉起"
fi
sleep "$CHECK_INTERVAL"
done
运行监测脚本指令,返回的信息大于0说明运行成功了。注意:先开启服务,再开启监测脚本。
nohup bash MonitoringScripts.sh & #运行
至此整个监测进程就搭建完成了。
补充:本文可以搭配这个场景使用。https://blog.hbb.cloudns.org/article/000011/.html
