终止laravel长运行脚本需通过跨进程管理:先在handle()开头写pid文件,退出时清理;再用自定义terminate命令按名或批量kill进程;队列worker优先发sigterm或用--stop-when-empty优雅退出。

在 Laravel 命令行中终止长时间运行的脚本,关键不是“中断当前正在执行的 PHP 代码”,而是停止它所对应的系统进程。因为 Artisan 命令一旦启动,就成为一个独立的、持续运行的 CLI 进程(比如数据抓取、长轮询服务或队列 worker),PHP 层面的 die() 或 exit() 在它已卡死或阻塞时往往无法触发。所以真正有效的方式是跨进程管理——记录 PID 并用系统命令杀掉。
给脚本加 PID 记录,方便精准定位
让长期运行的命令自己写一个 PID 文件,这是后续终止操作的前提:
- 在命令的
handle()方法开头,立即写入当前进程 ID 到 storage 目录下,文件名建议用命令名标准化(如data-crawler.pid) - 使用
file_put_contents(storage_path('app/data-crawler.pid'), getmypid()) - 务必在
finally块或正常退出前调用unlink()清理该文件,避免误判“假运行”
用自定义 Artisan 命令统一终止
创建一个 command:terminate 命令,支持按名称或全部清理:
- 执行
php artisan command:terminate data:crawler,它会读取data-crawler.pid,获取 PID,再调用kill(Linux/macOS)或taskkill(Windows)结束进程 - 不带参数时(
php artisan command:terminate),遍历所有*.pid文件,逐个清理对应进程 - 注意:Windows 下需用
taskkill /PID {pid} /F;Linux 下用kill -9 {pid}或更温和的kill {pid}
对队列 worker 的特殊处理
如果你运行的是 php artisan queue:work 类型的常驻进程,不要直接 kill,优先尝试优雅退出:
- 发送
SIGTERM信号:Linux 下可执行kill {pid}(非-9),前提是你的 worker 已注册pcntl_signal(SIGTERM, ...)回调 - 用内置参数控制:启动时加
--stop-when-empty,让它处理完当前队列后自动退出;适合部署更新或维护场景 - 通过进程管理器(如 Supervisor)重启:运行
sudo supervisorctl restart your-queue-worker,比手动 kill 更安全可靠
补充:别依赖 set_time_limit() 或 timeout 属性来“终止”运行中脚本
这些机制只在任务开始执行前生效,用于防止新任务无限卡住,并不能中断已经跑起来的循环或阻塞调用(比如没设超时的 cURL、sleep、file_get_contents):
-
$timeout = 120是 Laravel 队列 worker 对单个任务的监控上限,超时后抛异常并标记失败,但不会强行 kill 进程 -
set_time_limit(0)可用于长连接路由,但在 CLI 命令里基本无效——因为 queue:work 本身就是长生命周期进程,计时器不断重置 - 真要中断内部操作(如强制退出一个
while(true)循环),得靠外部信号(SIGALRM)或主动检查退出标记(如 Redis key、本地文件)











