You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无Supervisor的Laravel 10队列Worker托管服务器优化配置

无Root权限下Laravel 10队列Worker的优化方案(Hetzner托管环境)

现有方案与问题

在Hetzner托管服务器(仅SSH权限,无法使用Supervisor)中,当前通过Laravel调度实现队列Worker管理,代码如下:

// app/Console/Kernel.php
$schedule->call(function() use ($phpShellCmd) {
    shell_exec("php ".base_path()."/artisan queue:restart");
    file_put_contents(storage_path()."/logs/scheduler.log", "[".date('Y-m-d H:i:s')."] queue:restart executed.\n", FILE_APPEND);
})->everyMinute();

for($i = 0; $i < $num_of_workers; $i++) {
    $schedule->call(function() use ($i, $laravelbasedir) {
        $cmd = "php ".base_path()."/artisan queue:work --queue=MainQueue,OrderQueue --timeout=60 >> ".storage_path()."/logs/queueworker.log 2>/dev/null >/dev/null &";
        file_put_contents(storage_path()."/logs/scheduler.log", "[".date('Y-m-d H:i:s')."] execute queue:work #".($i+1).":".$cmd."\n", FILE_APPEND);
        shell_exec($cmd);
    })->everyMinute()->runInBackground();
}

设计思路与问题点

  • 设计思路:每分钟优雅重启队列+启动指定数量Worker,实现代码更新自动生效、Worker崩溃自动恢复,通过60秒超时控制进程数量。
  • 现存问题:任务实际运行时长超过60秒,多数情况正常但偶尔触发超时错误(提示"任务尝试次数过多或运行过久",无实际异常信息);频繁重启导致正在运行的任务被强制终止,引发不必要的重试;每分钟启动新Worker易造成进程冗余。

优化方案(无需Root/Supervisor)

方案1:进程监控脚本+Laravel调度

取消频繁重启逻辑,改用脚本监控Worker进程数量,仅在进程不足时补充。

实现步骤

  1. 创建Shell监控脚本queue-monitor.sh:
#!/bin/bash
NUM_WORKERS=3
BASE_DIR=/path/to/your/laravel
LOG_FILE=$BASE_DIR/storage/logs/queueworker.log
SCHEDULER_LOG=$BASE_DIR/storage/logs/scheduler.log

# 统计当前活跃的queue:work进程数
CURRENT_WORKERS=$(ps aux | grep "php artisan queue:work" | grep -v grep | wc -l)

# 补充缺失的Worker
while [ $CURRENT_WORKERS -lt $NUM_WORKERS ]; do
    nohup php $BASE_DIR/artisan queue:work --queue=MainQueue,OrderQueue --timeout=180 --tries=3 --sleep=5 --max-jobs=100 >> $LOG_FILE 2>&1 &
    CURRENT_WORKERS=$((CURRENT_WORKERS + 1))
    echo "[$(date '+Y-m-d H:i:s')] Started new worker. Total: $CURRENT_WORKERS" >> $SCHEDULER_LOG
done
  1. 在Laravel调度中添加脚本调用:
// app/Console/Kernel.php
$schedule->exec(base_path('queue-monitor.sh'))->everyMinute()->runInBackground();
  1. 给脚本添加执行权限:chmod +x queue-monitor.sh

优缺点

  • 优点:减少频繁重启的资源消耗,Worker可处理指定数量任务后再退出(--max-jobs);超时时间可匹配实际任务时长,避免误杀正常任务。
  • 缺点:需维护Shell脚本,进程统计依赖ps命令输出,兼容性有限;代码更新后需手动执行php artisan queue:restart。

方案2:Laravel调度内进程校验

直接在Laravel调度中检查Worker进程状态,仅启动缺失的Worker。

实现代码

// app/Console/Kernel.php
$schedule->call(function () use ($num_of_workers) {
    $basePath = base_path();
    $logPath = storage_path('logs/queueworker.log');
    $schedulerLog = storage_path('logs/scheduler.log');
    
    for ($i = 0; $i < $num_of_workers; $i++) {
        // 通过Worker ID校验进程是否存在
        $processCheck = shell_exec("ps aux | grep 'queue:work --queue=MainQueue,OrderQueue --worker-id=$i' | grep -v grep");
        if (empty($processCheck)) {
            $cmd = "nohup php $basePath/artisan queue:work --queue=MainQueue,OrderQueue --timeout=180 --tries=3 --sleep=5 --worker-id=$i >> $logPath 2>&1 &";
            shell_exec($cmd);
            file_put_contents($schedulerLog, "[" . date('Y-m-d H:i:s') . "] Started missing worker #$i: $cmd\n", FILE_APPEND);
        }
    }
})->everyMinute()->runInBackground();

优缺点

  • 优点:无需额外Shell脚本,直接通过Laravel调度管理;--worker-id标识避免重复启动进程。
  • 缺点:进程校验依赖ps命令输出,健壮性不足;代码更新后仍需手动触发队列重启。

方案3:用户级systemd服务(推荐)

Hetzner服务器支持用户级systemd服务(无需Root权限),可实现类似Supervisor的进程管理。

实现步骤

  1. 创建systemd服务文件~/.config/systemd/user/laravel-queue@.service:
[Unit]
Description=Laravel Queue Worker %I
After=network.target

[Service]
WorkingDirectory=/path/to/your/laravel
ExecStart=/usr/bin/php artisan queue:work --queue=MainQueue,OrderQueue --timeout=180 --tries=3 --sleep=5
Restart=always
RestartSec=10
User=your-ssh-username
StandardOutput=append:/path/to/your/laravel/storage/logs/queueworker-%I.log
StandardError=append:/path/to/your/laravel/storage/logs/queueworker-%I.log

[Install]
WantedBy=default.target
  1. 启用并启动多个Worker实例:
systemctl --user daemon-reload
# 启动3个Worker示例
for i in {1..3}; do
    systemctl --user enable --now laravel-queue@$i.service
done
  1. 常用管理命令:
# 查看单个Worker状态
systemctl --user status laravel-queue@1.service
# 重启所有Worker
systemctl --user restart laravel-queue@*.service
# 实时查看日志
journalctl --user -u laravel-queue@1.service -f

优缺点

  • 优点:最接近Supervisor的稳定体验,自动重启崩溃Worker;日志管理清晰,代码更新后执行php artisan queue:restart即可优雅重启所有Worker;无需依赖Laravel调度,资源消耗更低。
  • 缺点:需了解systemd基础配置;极少数共享托管环境可能限制用户级systemd服务,但Hetzner VPS/独立服务器均支持。

问题根源总结

现有方案的核心问题:

  1. 每分钟queue:restart强制终止正在运行的Worker,导致未完成任务被标记为超时并触发重试。
  2. 每分钟启动新Worker,易造成进程冗余,增加服务器负载。
  3. --timeout=60设置的是Worker最大运行时长,而非任务超时,强制终止长耗时任务引发错误。

内容的提问来源于stack exchange,提问作者alexandre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 23:40:56