1.问题

erp项目,每个商户一个站点,每个站点都需要配置4个supervisor进程,非常麻烦,而且很容易出错,故使用.ini配置文件方式来控制进程

2.执行脚本

#!/bin/bash

# 获取脚本的绝对路径
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# 定义 .env 文件路径(上上层目录:父目录的父目录)
PARENT_DIR=$(dirname "$SCRIPT_DIR")
GRANDPARENT_DIR=$(dirname "$PARENT_DIR")
ENV_PATH="$GRANDPARENT_DIR/.env"

# 检查 .env 文件是否存在
if [ ! -f "$ENV_PATH" ]; then
    echo "错误: 找不到 .env 文件"
    exit 1
fi

# 安全地读取 .env 文件
while IFS= read -r line || [[ -n "$line" ]]; do
    # 跳过空行和注释
    if [[ -z "$line" ]] || [[ "$line" =~ ^[[:space:]]*# ]]; then
        continue
    fi

    # 移除 export 关键字和空格
    line_clean=$(echo "$line" | sed 's/^export[[:space:]]*//')

    # 提取键值对
    key=$(echo "$line_clean" | cut -d '=' -f1 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
    value=$(echo "$line_clean" | cut -d '=' -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')

    # 去除可能的引号
    value=$(echo "$value" | sed -e "s/^['\"]//;s/['\"]$//")

    # 根据键设置变量(注意:.env 中是大写的 PATH 和 NUM)
    case "$key" in
        PATH)
            path="$value"
            ;;
        NUM)
            num="$value"
            ;;
    esac
done < "$ENV_PATH"

# 检查必需的变量
if [ -z "${path}" ]; then
    echo "错误: .env 文件中缺少 'PATH' 配置"
    exit 1
fi

if [ -z "${num}" ]; then
    echo "错误: .env 文件中缺少 'NUM' 配置"
    exit 1
fi

# 构建文件路径
expire="$path/public/supervisor/expire.ini"
expire_notice="$path/public/supervisor/expire_notice.ini"
free_call_num="$path/public/supervisor/free_call_num.ini"
socket="$path/public/supervisor/socket.ini"

# supervisor 配置路径
supervisor_path="/www/server/panel/plugin/supervisor/profile"
supervisor_expire="$supervisor_path/hsl_expire_$num.ini"
supervisor_expire_notice="$supervisor_path/hsl_expire_notice_$num.ini"
supervisor_free_call_num="$supervisor_path/hsl_free_call_num_$num.ini"
supervisor_socket="$supervisor_path/hsl_socket_$num.ini"

# 创建一个函数来处理文件复制和替换逻辑
process_file() {
    local source_file="$1"
    local target_file="$2"

    if [ -e "$source_file" ]; then
        # 读取文件内容
        content=$(cat "$source_file")

        # 替换 %path% 和 %num%(注意模板中的占位符是小写)
        # 将模板中的小写占位符替换为实际值
        replaced_content=$(echo "$content" | sed "s|%path%|$path|g; s|%num%|$num|g")

        # 检查目标文件是否存在
        if [ ! -e "$target_file" ]; then
            echo "$replaced_content" > "$target_file"
            $(/www/server/panel/pyenv/bin/supervisorctl update)
        else
            # 目标文件存在,比较内容
            if ! echo "$replaced_content" | diff -q "$target_file" - > /dev/null 2>&1; then
                echo "更新文件: $target_file"
                echo "$replaced_content" > "$target_file"
                $(/www/server/panel/pyenv/bin/supervisorctl update)
            else
                echo "文件内容相同,无需更新: $target_file"
            fi
        fi
    else
        echo "警告: 源文件不存在: $source_file"
    fi
}

# 处理每个文件
process_file "$expire" "$supervisor_expire"
process_file "$expire_notice" "$supervisor_expire_notice"
process_file "$free_call_num" "$supervisor_free_call_num"
process_file "$socket" "$supervisor_socket" "socket_"
echo "处理完成!"

3. 配置文件–.ini

[program:hsl_expire_%num%]
command=php think queue:listen --queue=expire_%num%
directory=%path%
autorestart=true
startsecs=3
startretries=3
stdout_logfile=/www/server/panel/plugin/supervisor/log/expire_%num%.out.log
stderr_logfile=/www/server/panel/plugin/supervisor/log/expire_%num%.err.log
stdout_logfile_maxbytes=2MB
stderr_logfile_maxbytes=2MB
user=www
priority=999
numprocs=1
process_name=%(program_name)s_%(process_num)02d

4.注意

1.program的hsl的前缀目的是服务器异常的时候同时查出来这个进程,方便杀死
2.宝塔里面的supervisor要求文件名和进程名必须完全一致,所以会有修改文件这一步--文件名和.ini里面的program名称保持一致
3.源文件是是public/supervisor的文件,写入到宝塔的supervisor配置文件
4. 原理:手写supervisor的配置文件,并且读取成功之后放到宝塔的supervisor配置目录下,然后重启supervisor服务