【问题标题】:Laravel - Running Jobs in SequenceLaravel - 按顺序运行作业
【发布时间】:2019-03-30 06:16:52
【问题描述】:

我正在学习 Laravel,正在从事一个运行 Horizo​​n 以了解工作的项目。我被困在一个地方,我需要一个接一个地运行相同的工作几次。

这是我目前正在做的事情

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\Subscriptions;
class MailController extends Controller
{


    public function sendEmail() {
        Subscriptions::all()
        ->each(function($subscription) {
            SendMailJob::dispatch($subscription);
        });
    }
}

这很好用,除了它在多个工人之间运行作业并且没有保证的顺序。有没有办法一个接一个地运行作业?

【问题讨论】:

    标签: laravel laravel-5 redis laravel-queue laravel-horizon


    【解决方案1】:

    正如您在问题中提到的那样,您正在寻找的是工作链。

    From the Laravel docs

    作业链允许您指定应按顺序运行的排队作业列表。如果序列中的一个作业失败,则不会运行其余作业。要执行排队作业链,您可以在任何可调度作业上使用 withChain 方法:

    ProcessPodcast::withChain([
        new OptimizePodcast,
        new ReleasePodcast
    ])->dispatch();
    

    所以在你上面的例子中

    $mailJobs = Subscriptions::all()
        ->map(function($subscription) {
            return new SendMailJob($subscription);
        });
    
    Job::withChain($mailJobs)->dispatch()
    

    应该会给出预期的结果!

    更新

    如果您不想使用初始作业进行链接(如上面的文档示例中所示),您应该能够创建一个具有use Dispatchable; 的空Job 类。然后你可以使用我上面的例子

    【讨论】:

    • 感谢您的回答,没有问题,Job 课程来自哪里。
    • 嘿,乔希,您的解决方案运行良好。但是当一项工作失败时,整个链条都会停止。
    • 嗨 Vish,是的,这是一个不幸的缺点。如果你设计你的工作不会失败,这仍然是可以接受的。我的意思是:您应该将失败的作业视为应用程序中的错误(而不是预期的异常)。因此,您可以使用 try、catch、validation 等...来避免工作实际失败。当然,这是一个设计决定,您必须考虑最适合您的情况! :)
    • 谢谢,我也在尝试 Redis 油门。
    • 链接的一个特殊特性是,链中的下一个作业只有在前一个作业没有失败的情况下才会运行。这不是缺点。这是设计和预期的行为。要按顺序运行一系列作业而不依赖于成功,请将它们全部发送到同一个队列,并在该队列上运行一个工作人员。工人一次只能处理一项工作。
    【解决方案2】:

    一切都取决于您将运行多少个队列工作人员

    如果您运行单队列工作者,那些jobs 将按照它们排队的顺序进行处理。但是,如果您运行多个队列工作人员,显然它们将同时运行。这就是队列的工作方式。您添加一些任务,它们可能会以不同的顺序同时运行。

    当然,如果你想确保jobs 之间有一个暂停,你可以在each 中添加一些sleep() 但假设你在控制器中运行它(可能这不是一个好主意,因为万一你有百万订阅)它可能不是最好的解决方案。

    【讨论】:

    • 感谢您的回答。我正在寻找像 dispatch->chain([new MailJob($item1), new MailJob($item2), new MailJob($item3)]) 这样的解决方案
    • Chaining 执行您在问题中描述的操作,但您声明这不是您想要的。这个答案提供了您所要求的功能。它应该是选择的答案。
    【解决方案3】:

    您需要的是作业链。

    您可以在 Laravel 网站上阅读所有相关信息:Chain

    祝你好运

    【讨论】:

      【解决方案4】:

      要添加关于@Josh 答案的额外信息,如果您的一个作业实现了Illuminate\Contracts\Queue\ShouldQueue 接口,则链中的其他作业必须实现ShouldQueue 接口,否则它们将不会被链接。

      例如,这里如果ProcessPodcast类实现了ShouldQueueOptimizePodcast也必须实现这个接口才能被包含在链中。

      class ProcessPodcast implements ShouldQueue {
          use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
          ...
      }
      
      class OptimizePodcast implements ShouldQueue {
          use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
          ...
      }
      

      【讨论】:

        猜你喜欢
        • 2021-05-23
        • 1970-01-01
        • 2018-08-01
        • 2019-03-27
        • 1970-01-01
        • 2019-09-07
        • 2012-03-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多