守护进程模式下 平滑重启方案

ichynul

守护进程模式下,需要运行命令

守护模式更新代码要到服务器上操作,如果开发人员没有服务器权限就不好办。
只能退而求其次,使用Supervisor之类的不加-d运行,但这种模式有个弊端,每次更新代码都会短暂502,好像还没好的办法解决(需要多套程序负载均衡)。

为此你搜索到了哪些方案及不适用的原因

问了AI,可以定时检测目录下reloadrestart两个文件,有就执行相关命令。
试了下,这种方案可行。
有没有办法在框架层面实现类似的?在Master进程应该能做到吧

#!/bin/bash

# ===================== 项目路径配置 =====================
PROJECTS=(
"/www/wwwroot/project1"
"/www/wwwroot/project2"
"/www/wwwroot/project3"
)
# ======================================================

PHP_BIN="php"
LOG_DIR="/var/log/webman_manager"
mkdir -p "$LOG_DIR"

# 每天一个日志文件
LOG_FILE="$LOG_DIR/webman_manager_$(date +%Y-%m-%d).log"

# 日志输出函数
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

# 自动清理 7 天前日志
find "$LOG_DIR" -name "webman_manager_*.log" -mtime +7 -delete

log "===== 开始检测项目 ====="

# 遍历项目
for PROJECT in "${PROJECTS[@]}"; do
    if [ ! -d "$PROJECT" ]; then
        log "项目不存在,跳过:$PROJECT"
        continue
    fi

    if [ ! -f "$PROJECT/start.php" ]; then
        log "非 Webman 项目,跳过:$PROJECT"
        continue
    fi

    # ==================== reload 平滑重启 ====================
    if [ -f "$PROJECT/reload" ]; then
        log "检测到 reload,执行平滑重启:$PROJECT"

        # 执行并把输出 全部写入日志
        cd "$PROJECT"
        $PHP_BIN start.php reload -g >> "$LOG_FILE" 2>&1

        rm -f "$PROJECT/reload"
        log "reload 执行完成,文件已删除"
    fi

    # ==================== restart 强制重启 ====================
    if [ -f "$PROJECT/restart" ]; then
        log "检测到 restart,执行强制重启:$PROJECT"

        # 执行并把输出 全部写入日志
        cd "$PROJECT"
        $PHP_BIN start.php restart -d >> "$LOG_FILE" 2>&1

        rm -f "$PROJECT/restart"
        log "restart 执行完成,文件已删除"
    fi
done

log "===== 本轮检测完成 ====="

这里提几个坑,文档里面没有详细说明,不翻代码查资料就搞不明白。
1、-d 守护模式时,重启restart命令也必须带 -d
2、realod -gupstream 里面的 keepalive 10240 貌似冲突(AI说的)

问题归纳总结:

stop_timeout设为30,仍然感觉一些绝对不可能耗时那么久的接口被强杀。
我猜测可能是某些接口确实耗时比较长,比如定时任务、还有一个生成个人二维码的要下载远程图片。
因为开启协程,所以一个worker里面会同时有多个请求,如果其中一个协程耗时比较长,那这个worker就一直无法关闭。
在这期间还仍然开启其他协程继续接收请求,直到stop_timeout超时。所以给人的错觉是,有些接口明显是不可能耗时那么久的,还是被强杀了。
解决方法当然是区分快慢接口,把耗时就的放在单独一个端口:https://www.workerman.net/doc/webman/others/task.html

433 5 0
5个回答

Mr.Gong

你可以在gitea或github的webhook针对分支设置回调勾子,请求你的项目地址,在接口接收到合并请求或master、product分支推送的操作类型时,推送队列消费执行sehll命令重启服务。
这样可以实现服务随代码变更自动重启

  • 暂无评论
qqxxr

可以把热更新打开呀,webman自带的功能

  • ichynul 2026-04-17

    已经说了呀,502问题。访问量大的时候,刚好你更新代码的时候有人访问,就报网络错误

  • ichynul 2026-04-17

    别说用户,就是我自己都经常遇到上传了代码,然后去访问报502。这中间有多少时间间隔,怕有1~2秒钟

  • mass_wm 2026-04-17

    我也用的热更新,用了两年多webman,没碰到过更新完502的情况

  • 故人重来 2026-04-18

    stop_timeout 是执行stop时进程如果还在处理业务就等待,如果等待时间超过stop_timeout设置的时间,则执行强制杀死进程。
    你平滑重启有过度时间的

  • ichynul 2026-04-20

    奇怪难道是我代码的问题,或者是与reusePort为false有关?

evilk

可以设置 'stop_timeout' => 30, // 收到stop/restart/reload信号时,等待处理完成的最大时间,超过这个时间进程未退出则强制退出

  • ichynul 2026-04-19

    这个就有设置过10秒,上传完代码再访问接口,绝对没10秒

  • evilk 2026-04-20
    1. 我们线上, 设置的stop_timeout是30秒
    2. 每次更新, 都是, 先更新代码, 然后restart
    3. 自从上线以来, 从来没遇见过502
  • ichynul 2026-04-21

    你这是守护模式吗?我现在换成守护模式,更新完代码再手动restart,也没遇到502了

  • evilk 2026-04-21
    1. 线上, 肯定是守护模式啊, php start.php start -d
    2. 发布更新的时候, 就直接 php start.php restart -d
  • qqxxr 2026-04-24

    守护进程模式,并且开启热更新

ersic

直接 docker 吧

  • 暂无评论
4yop

双机热备呗;临时再启动一个节点去使用;进行切换;

  • 暂无评论
🔝