本文目录导读:

Shell脚本实现热加载(即在不重启进程的情况下重新加载配置或代码)主要有以下几种方法:
信号机制(最常用)
#!/bin/bash
# 配置文件
CONFIG_FILE="/etc/myapp/config.conf"
PID_FILE="/var/run/myapp.pid"
# 信号处理函数
reload_config() {
echo "重新加载配置: $(date)"
source "$CONFIG_FILE"
# 这里执行配置生效的逻辑
}
# 注册信号处理器
trap reload_config SIGHUP
# 主循环
while true; do
# 业务逻辑
echo "运行中..."
sleep 5
done
使用方法:
# 启动 ./script.sh & # 热加载 kill -HUP <PID> # 或者 pkill -HUP script.sh
文件监控方式
#!/bin/bash
# 监控配置文件变化
CONFIG_FILE="/etc/myapp/config.conf"
LAST_MODIFIED=$(stat -c %Y "$CONFIG_FILE")
reload_config() {
echo "检测到配置文件变化,重新加载..."
source "$CONFIG_FILE"
# 执行配置生效逻辑
}
while true; do
CURRENT_MODIFIED=$(stat -c %Y "$CONFIG_FILE")
if [ "$CURRENT_MODIFIED" != "$LAST_MODIFIED" ]; then
LAST_MODIFIED=$CURRENT_MODIFIED
reload_config
fi
sleep 2
done
使用inotify(Linux专用)
#!/bin/bash
# 需要安装 inotify-tools
# apt-get install inotify-tools
CONFIG_FILE="/etc/myapp/config.conf"
reload_config() {
echo "配置文件变更,重新加载..."
source "$CONFIG_FILE"
}
# 监控文件变化
inotifywait -m -e modify "$CONFIG_FILE" |
while read -r directory events filename; do
reload_config
done
动态函数重载
#!/bin/bash
# 函数库文件
FUNCTIONS_FILE="./functions.sh"
# 热加载函数
hot_reload_function() {
local func_name=$1
local func_file=$2
# 重新加载特定函数
eval "$(sed -n "/^${func_name}()/,/^}/p" "$func_file")"
}
# 主程序逻辑
while true; do
# 业务逻辑
if [ -f "$FUNCTIONS_FILE" ]; then
hot_reload_function "my_function" "$FUNCTIONS_FILE"
fi
sleep 10
done
完整示例:配置热加载服务
#!/bin/bash
# 配置热加载服务
CONFIG_FILE="/tmp/app.conf"
PID_FILE="/tmp/app.pid"
LOG_FILE="/tmp/app.log"
# 默认配置
PORT=8080
MODE="production"
TIMEOUT=30
# 初始化配置
init_config() {
if [ -f "$CONFIG_FILE" ]; then
source "$CONFIG_FILE"
fi
log "配置初始化完成: PORT=$PORT, MODE=$MODE"
}
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}
# 重新加载配置
reload_config() {
log "收到重载信号,重新加载配置..."
OLD_PORT=$PORT
OLD_MODE=$MODE
OLD_TIMEOUT=$TIMEOUT
init_config
if [ "$PORT" != "$OLD_PORT" ] || [ "$MODE" != "$OLD_MODE" ]; then
log "配置变更: PORT=$OLD_PORT->$PORT, MODE=$OLD_MODE->$MODE"
fi
apply_config
}
# 应用配置
apply_config() {
# 模拟配置生效
log "应用新配置: PORT=$PORT, MODE=$MODE, TIMEOUT=$TIMEOUT"
}
# 服务主循环
service_loop() {
log "服务启动,PID=$$"
echo $$ > "$PID_FILE"
while true; do
# 模拟服务运行
sleep 5
log "服务运行中: PORT=$PORT, MODE=$MODE"
done
}
# 信号处理
trap reload_config SIGHUP
trap 'log "服务停止"; rm -f "$PID_FILE"; exit 0' SIGTERM SIGINT
# 启动服务
init_config
apply_config
service_loop
管理脚本
#!/bin/bash
SERVICE_SCRIPT="./hot_reload_service.sh"
PID_FILE="/tmp/app.pid"
start() {
if [ -f "$PID_FILE" ]; then
echo "服务已在运行"
return 1
fi
nohup bash "$SERVICE_SCRIPT" > /dev/null 2>&1 &
echo "服务已启动"
}
stop() {
if [ -f "$PID_FILE" ]; then
kill -TERM $(cat "$PID_FILE") 2>/dev/null
rm -f "$PID_FILE"
echo "服务已停止"
else
echo "服务未运行"
fi
}
reload() {
if [ -f "$PID_FILE" ]; then
kill -HUP $(cat "$PID_FILE") 2>/dev/null
echo "已发送重载信号"
else
echo "服务未运行"
fi
}
status() {
if [ -f "$PID_FILE" ] && kill -0 $(cat "$PID_FILE") 2>/dev/null; then
echo "服务运行中,PID: $(cat $PID_FILE)"
else
echo "服务未运行"
fi
}
case "$1" in
start) start ;;
stop) stop ;;
reload) reload ;;
status) status ;;
*)
echo "用法: $0 {start|stop|reload|status}"
exit 1
;;
esac
使用示例
# 启动服务 ./manage.sh start # 修改配置文件 echo "PORT=9090" > /tmp/app.conf # 热加载 ./manage.sh reload # 查看状态 ./manage.sh status # 停止服务 ./manage.sh stop
关键点
- 信号处理:使用
trap捕获 SIGUP 信号 - 日志记录:记录重载事件和配置变更
- 优雅处理:确保重载过程中服务不中断
- 配置验证:在应用配置前进行验证
- 回滚机制:配置错误时可以回滚到上一版本
这种热加载方式适用于配置变更、函数更新等场景,无需重启进程即可生效。