Laravel作业在执行长任务时会运行多次

时间:2019-08-06 15:45:19

标签: laravel laravel-queue ffmpeg-php laravel-jobs

我目前正在尝试将视频转换为多个.ts片段(用于HTTP视频流)。这是一项艰巨的任务,所以我要在Laravel中完成这项工作。

问题在于,作业在几分钟后运行了多次,因此,视频被多次处理。在这里,您可以看到我的Job班级:

<?php

namespace App\Jobs;

use App\Models\Media\MediaFile;
use FFMpeg\Filters\Video\ResizeFilter;
use FFMpeg\Format\Video\X264;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use FFMpeg;

class ConvertVideoForStreaming implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;


    public $mediaFile;
    public $deleteWhenMissingModels = true;
    public $timeout = 3600;
    public $retryAfter = 4000;
    public $tries = 3;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct(MediaFile $mediaFile)
    {
        $this->mediaFile = $mediaFile;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        $this->mediaFile->update([
            'status' => 'Processing',
            'status_message' => null,
        ]);


        $convertingId = Str::random(6);


        $lowBitrateFormat  = (new X264('aac', 'libx264'))
            ->setKiloBitrate(500)
            ->setAudioKiloBitrate(128);
        $midBitrateFormat  = (new X264('aac', 'libx264'))
            ->setKiloBitrate(1500)
            ->setAudioKiloBitrate(192);
        $highBitrateFormat = (new X264('aac', 'libx264'))
            ->setKiloBitrate(3000)
            ->setAudioKiloBitrate(256);

        \Log::info('Started a new converting process with convertingID: ' . $convertingId);

        FFMpeg::fromDisk('public')
            ->open($this->mediaFile->file)
            ->exportForHLS()
            ->setSegmentLength(4) // optional
            ->addFormat($lowBitrateFormat, function($media) {
                $media->addFilter(function ($filters) {
                    $filters->resize(new \FFMpeg\Coordinate\Dimension(640, 480), ResizeFilter::RESIZEMODE_INSET);
                });
            })
            ->addFormat($midBitrateFormat, function($media) {
                $media->addFilter(function ($filters) {
                    $filters->resize(new \FFMpeg\Coordinate\Dimension(1280, 720), ResizeFilter::RESIZEMODE_INSET);
                });
            })
            ->addFormat($highBitrateFormat, function($media) {
                $media->addFilter(function ($filters) {
                    $filters->resize(new \FFMpeg\Coordinate\Dimension(1920, 1080), ResizeFilter::RESIZEMODE_INSET);
                });
            })
            ->onProgress(function ($percentage) use($convertingId)  {
                \Log::info($this->mediaFile->name . " (ConvertingID: $convertingId) - $percentage % transcoded");
                \Redis::set('video-transcoded-' . $this->mediaFile->id, $percentage);
            })
            ->toDisk('public')
            ->save('livestream/' . Str::slug($this->mediaFile->name) . '/playlist.m3u8');

        $this->mediaFile->update([
            'status' => 'Active',
            'status_message' => null,
        ]);

    }


    public function failed(\Exception $exception)
    {
        $this->mediaFile->update([
            'status' => 'Failed',
            'status_message' => $exception->getMessage(),
        ]);
    }

}

我该如何解决我的问题?

1 个答案:

答案 0 :(得分:0)

Laravel为计划的命令提供了“锁定”功能。请参阅this文档中的“防止任务重叠”。

如果您只希望一次处理非计划作业,我建议您研究Symfony Lock Component。该组件使您可以锁定某个任务一段时间或直到将其解锁。这样,您可以按照以下方式进行操作:

  1. handle()方法的开头
    一种。检查锁是否已经存在,否则跳过此作业
    b。如果该锁不存在,请创建它
  2. 执行长期运行的任务
  3. handle()逻辑的最后,释放锁