1

我目前正在尝试将视频转换为多个 .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(),
        ]);
    }

}

我该如何解决我的问题?

4

1 回答 1

0

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

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

  1. 在您的handle()方法开始
    时 检查锁是否已经存在,否则跳过此作业
    b. 如果锁不存在,则创建它
  2. 执行您长时间运行的任务
  3. 在你的handle()逻辑结束时释放锁
于 2019-08-06T16:48:28.983 回答