
Laravel 开发环境下使用 php artisan serve 运行长时 Shell 命令(如 FFmpeg 视频处理)会阻塞整个应用,导致所有请求挂起;根本原因在于 PHP 内置服务器的单进程、单线程设计,而非 Session 锁问题。
laravel 开发环境下使用 `php artisan serve` 运行长时 shell 命令(如 ffmpeg 视频处理)会阻塞整个应用,导致所有请求挂起;根本原因在于 php 内置服务器的单进程、单线程设计,而非 session 锁问题。
在构建视频编辑类应用(如基于 Laravel 8 的 FFmpeg 处理服务)时,常通过 AJAX 触发后端长时间运行的 Shell 命令(例如 shell_exec('ffmpeg -i ...'))。开发者往往误以为阻塞源于 Laravel 的 Session 写入锁,进而尝试 session()->save() 或 session_write_close() —— 但这些操作在 php artisan serve 环境下无法解决问题,因为症结不在 Session,而在于底层 Web 服务器架构。
? 根本原因:php artisan serve 的局限性
php artisan serve 启动的是 PHP 内置的单线程开发服务器(基于 php -S),它一次仅能处理一个请求。当某个请求(如 FFmpeg 处理)长时间占用 PHP 进程时,后续所有 HTTP 请求(包括其他页面、AJAX、静态资源)都会排队等待,表现为“整个 localhost:8000 站点冻结”。这与 Apache/Nginx + PHP-FPM 环境完全不同——后者支持并发多进程/多线程,可同时响应多个请求,即使一个请求执行 10 分钟,也不影响其他用户访问。
✅ 正确解决方案:切换至生产级 Web 服务器
不要在开发或生产中依赖 php artisan serve 执行耗时任务。 推荐做法如下:
- 本地开发环境:使用 Laravel Valet(macOS)、Laragon(Windows)或配置 Apache/Nginx + PHP-FPM;
-
Docker 环境:通过
nginx:alpine+php:8.2-fpm组合运行; -
生产环境:必须部署于 Nginx/Apache + PHP-FPM,并确保
pm.max_children等参数合理配置。
✅ 示例(Nginx + PHP-FPM 配置片段):
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000; # 或 unix:/var/run/php/php8.2-fpm.sock
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}⚠️ 补充建议:增强健壮性(非替代方案)
尽管切换 Web 服务器是核心解法,以下实践仍值得同步实施:
- 使用队列(如
php artisan queue:work --daemon)异步执行 FFmpeg,避免阻塞 HTTP 进程; - 通过
nohup ffmpeg ... &或proc_open()启动后台进程,并记录 PID 便于状态监控; - 前端轮询
/api/job-status/{id}或使用 SSE/WebSocket 实时反馈进度; - 在命令前添加超时与错误重定向:
$command = "timeout 600 ffmpeg -i {$input} -c:v libx264 {$output} 2>&1"; $output = shell_exec($command);
? 提示:若临时需验证逻辑,可在 CLI 下运行
php artisan tinker测试命令,避开 Web 服务器限制;但切勿将php artisan serve用于任何含长耗时任务的场景。
综上,解决该问题的关键不是调用 session()->save(),而是摒弃 PHP 内置服务器,改用支持并发的 Web 服务栈——这是 Laravel 官方文档明确指出的开发与生产环境分离原则,也是保障应用可扩展性的基础。


















