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

如何在Laravel与cPanel中持续运行任务队列?

问题分析与解决方案

你的思路有可行性,但算不上最优方案,咱们拆解下问题,看看更合理的处理方式:

先搞清楚内存爆的根源

你用queue:listen不带--stop-when-empty时内存跑满,核心原因是Laravel的队列监听进程长期运行时容易出现内存泄漏,加上cPanel共享主机的内存配额通常不高,直接把可用内存占满了。

你的观察者方案的问题

给任务表加模型观察者,在created()事件触发queue:work --stop-when-empty,这个思路能触发任务处理,但有两个明显的坑:

  • 短时间内多个任务创建时,会启动多个独立的queue:work进程,反而会加剧内存占用,甚至可能超出主机进程数限制
  • 缺少进程管理机制,容易出现进程残留,时间久了一堆僵尸进程占资源

更优的替代方案

方案1:优化原定时任务(最适合共享主机)

不用改逻辑,直接给定时任务的队列命令加内存限制和超时参数:

php artisan queue:work --stop-when-empty --memory=128 --timeout=60

然后把执行频率调整为每2-5分钟一次(不用每分钟这么频繁)。

  • --memory=128:限制单进程最大占用128MB内存,到阈值自动退出,避免泄漏爆内存
  • --timeout=60:防止任务卡死后进程一直挂着
  • 因为你的BuyJob是队列任务,数据库队列默认是单进程串行处理的,只要任务进入队列,同一时间只会有一个BuyJob执行,完全能避免库存并发扣减的问题。

方案2:用进程守护工具(如果主机支持)

如果你的cPanel主机提供Supervisor或者自带的进程守护功能,直接配置一个持续运行的队列进程:

php artisan queue:work --daemon --memory=128 --timeout=60 --sleep=3
  • --daemon:让进程持续运行,处理完任务后休眠3秒再轮询(--sleep=3)
  • 同样通过--memory和--timeout控制资源占用,进程内存到限制会自动重启,既能保证队列持续监听,又不会爆内存。

方案3:给库存扣减加行锁(彻底摆脱队列持续运行的依赖)

其实不需要靠队列持续运行来防并发,直接在BuyJob的库存扣减逻辑里加数据库行锁:

// 在BuyJob的handle方法里
$product = DB::table('products')
    ->where('id', $this->productId)
    ->lockForUpdate()
    ->first();

// 这里处理库存扣减逻辑
if ($product->stock >= $this->quantity) {
    DB::table('products')->where('id', $this->productId)->decrement('stock', $this->quantity);
}

加了lockForUpdate后,即使多个BuyJob同时触发,数据库也会串行处理这些请求,保证库存扣减的原子性。这样你可以继续用原来的queue:listen --stop-when-empty定时任务,不用纠结队列是否持续运行。

总结

优先选方案1(共享主机最稳妥),如果主机支持进程守护就选方案2,观察者方案不推荐,容易引发进程和内存问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 11:09:27