Laravel中如何实现代码后台运行?以FFmpeg视频合并为例
Laravel后台运行视频合并代码的实现方案
一、使用Laravel任务队列(最推荐)
这是Laravel原生支持的异步处理方案,自带失败重试、进程监控等功能,完全适配耗时的视频处理场景。
步骤:
- 生成任务类
运行Artisan命令创建处理视频合并的任务:
php artisan make:job MergeVideoJob
- 编写任务逻辑
打开app/Jobs/MergeVideoJob.php,在handle方法里实现视频合并和状态更新:
<?php namespace App\Jobs; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; class MergeVideoJob implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; protected $video1; protected $video2; protected $id; public function __construct($video1, $video2, $id) { $this->video1 = $video1; $this->video2 = $video2; $this->id = $id; } public function handle() { // 执行FFmpeg合并命令 $cmd = "ffmpeg -i concat:{$this->video1}|{$this->video2} -c copy merged_{$this->id}.mp4"; exec($cmd); // 更新合并状态 updateStatusMerge($this->id, 'ready'); } }
- 在控制器中分发任务
修改你的video_merge方法,直接分发任务后立即返回响应:
public function video_merge() { $video1 = "video1.mp4"; $video2 = "video2.mp4"; $id = "xxxxxxxxxxxxx"; // 分发任务到队列,后台异步执行 \App\Jobs\MergeVideoJob::dispatch($video1, $video2, $id); return response()->json([ 'status' => 'processing', 'id' => $id ]); }
- 启动队列Worker
最后需要启动队列进程来处理任务:
php artisan queue:work
如果需要后台持久运行,可以用supervisor或者nohup来守护进程,避免进程意外终止。
二、直接修改exec命令让系统后台执行
如果不想依赖队列,也可以直接通过修改shell命令让FFmpeg在系统后台运行,同时把状态更新逻辑绑定到命令执行完成后。
实现方式:
把FFmpeg命令和状态更新命令用&&串联,确保合并完成后再更新状态,最后加上后台运行标识:
public function video_merge() { $video1 = "video1.mp4"; $video2 = "video2.mp4"; $id = "xxxxxxxxxxxxx"; // 拼接命令:先执行合并,完成后调用Artisan命令更新状态,后台运行 $cmd = "ffmpeg -i concat:$video1|$video2 -c copy merged_{$id}.mp4 && php " . base_path('artisan') . " app:update-merge-status $id > /dev/null 2>&1 &"; exec($cmd); return response()->json([ 'status' => 'processing', 'id' => $id ]); }
然后创建一个Artisan命令来处理状态更新:
php artisan make:command UpdateMergeStatus
打开app/Console/Commands/UpdateMergeStatus.php,编写逻辑:
<?php namespace App\Console\Commands; use Illuminate\Console\Command; class UpdateMergeStatus extends Command { protected $signature = 'app:update-merge-status {id}'; protected $description = 'Update video merge status'; public function handle() { $id = $this->argument('id'); updateStatusMerge($id, 'ready'); } }
这种方式的缺点是没有失败重试机制,若FFmpeg命令执行失败,状态不会更新,也缺少日志记录,仅适合简单场景。
三、使用Laravel Process类(替代exec)
Laravel提供了Illuminate\Support\Facades\Process类来执行系统命令,API更友好,也能实现后台运行:
use Illuminate\Support\Facades\Process; public function video_merge() { $video1 = "video1.mp4"; $video2 = "video2.mp4"; $id = "xxxxxxxxxxxxx"; // 后台运行命令,不阻塞当前请求 Process::timeout(3600)->runInBackground(function ($type, $output) { // 可选:在这里处理命令输出或日志 }, "ffmpeg -i concat:$video1|$video2 -c copy merged_{$id}.mp4 && php " . base_path('artisan') . " app:update-merge-status $id"); return response()->json([ 'status' => 'processing', 'id' => $id ]); }
这个方式和直接用exec逻辑类似,但Process类提供了更便捷的错误处理和输出控制。
内容的提问来源于stack exchange,提问作者lCode
相关产品推荐
相关产品推荐

