Laravel命令和任务

33

我想知道 Laravel 5.1 中的不同类命令之间有什么区别。据我所知,Laravel 5.1 可用以下命令:

  • 控制台命令(artisan make:console
  • 命令(artisan make:command
    • 处理器(artisan make::command --handler
  • 作业(artisan make:job

我是直接从4.2升级到5.1的,所以不知道4.2和5.1之间发生了什么,但我已经听说中间那个(仅仅是命令)基本上不再使用了 - 它们在队列化作业成为“命令”时出现在5.0中,但Laravel后来反对这一点,它们只是为了兼容性而存在。然而,我对此并不100%确定,希望能得到澄清。

我的具体用例是,我想要一个地方放置一个自包含的“可运行”任务。例如,从给定目录中删除早于5天的文件(但它可以执行任何操作)。

起初这听起来像是一个控制台命令 - 我想要能够从 artisan 运行它,首先。但我可能也想在时间表上运行它(非常好,artisan schedule:run 运行控制台命令)。但我也可能想要异步地从代码中执行它。控制台命令可以使用 synchronously 来运行 Artisan::call(),但对于异步来说,这是(我认为)队列派上用场,而它突然变成了一个作业。

好的,我们有一个任务。我们现在可以从代码中将它添加到队列中,但是如何将其作为artisan命令(同步)执行?我是否只需创建一个轻量级控制台命令,并添加DispatchesJobs特征(或其中的代码),然后调度该任务?任务总是必须进入队列中吗,还是我们可以使任务同步执行(并最好输出到控制台命令的输出中)?对于定时运行它的方式也是同样的问题-我应该创建这个控制台命令并将其添加到计划程序中,还是可以直接让计划程序运行任务?

最后,我们有“命令”既不是控制台命令,也不是任务。正如我之前所说,人们告诉我这些只是Laravel 5.0代码更改的附带影响(有点)被撤销了。但是artisan make命令仍然存在于它们身上,所以它们不能太过时。此外,“自处理命令”(默认情况下带有handle方法)和“需要”处理程序类的命令(运行artisan make:command --handler)是什么意思?你如何实际执行这些命令?手动使用(new App\Command\SomeCommand)->handle();(new App\handlers\SomeCommandHandler)->handle(new App\Command\SomeCommand),还是有一些我不知道的隐藏系统(也许它们可以使用作业/队列调度程序进行调度)?此外,您可以创建“排队”命令artisan make::command --queued,那么这些命令有何不同呢?

我想我的问题归结为以下几点:

  • 它们之间的真正(语义功能)区别是什么?
  • 运行它们的正确方法是什么?
  • 对于我需要以任何我觉得适当的方式运行的基本独立代码来说,哪种方法最好?

我在文档中找到了如何使用队列和创建控制台命令的信息,但没有关于何时使用它们或有关命令类和处理程序的详细信息。


相关但不完全相同(而且没有答案):Laravel 5.1 命令和作业

3个回答

30

控制台命令

Laravel 已经有了一段时间的控制台“commands”。它们基本上没有改变,也按照原来的方式运作。简单来说,它们相当于命令行的路由 - 是应用程序的入口点。它们与...

命令总线

Laravel 5.0 引入了Command Bus模式的实现,即命令总线(Command Bus)。 (由于与CLI命令产生的混淆,我认为这些已经被重命名为Jobs)。

命令总线由两部分组成 - 一个表示要执行的命令及其所需的任何和所有数据的对象(工作),以及执行命令的类(处理程序)。

处理程序

在 Laravel 中,您可以声明一个作业为自处理 - 即它自己有一个处理方法。

如果您想注册命令处理程序,则可以在服务提供程序中调用以下内容:

app('Illuminate\Bus\Dispatcher')->maps(['Job' => 'Handler']);

其中,Job是作业的类名称,Handler是处理程序的类名称。

Laravel 5.0中的handlers目录是一种隐式声明这些关系的方式(例如,命令文件夹中的EmailCommand将在处理程序文件夹中具有EmailCommandHandler)。

分派命令

您可以使用以下内容来分派命令。

app('Illuminate\Bus\Dispatcher')->dispatch(new EmailPersonCommand('email@you.com', $otherdata));

队列

默认情况下,作业将在调用(或分派)时立即运行。将它们设置为ShouldQueue将始终在调度时将它们传递到队列中。

如果您有时想要同步运行它们,有时想要异步运行它们,可以在希望将它们排队时调用$dispatcher->dispatchToQueue($job)。 当您将ShouldQueue作业传递给->dispatch()时,内部就会发生这种情况。

编辑:排队(或不排队)

我刚刚仔细查看了调度程序。 dispatch方法检查命令是否为ShouldQueue,并将其转发到dispatchToQueuedispatchNow。 如果您希望覆盖默认行为,可以直接调用这两种方法之一而不是dispatch与您的命令。

因此,在您的情况下,取决于作业的“默认”行为(即,它通常会排队吗?),可以采用以下两种方法之一: - 将其设置为ShouldQueue,并在CLI命令中使用dispatchNow。 - 不要将其设置为ShouldQueue,并在您的代码中调用dispatchToQueue

从听起来的情况来看,我会选择前者。


如果我编写的作业可以排队,但不必排队,那么我就不应该有ShouldQueue接口,因为它会使我的作业始终排队,即使我不总是需要。但是我仍然可以排队没有ShouldQueue的作业,对吗? - alexrussell
@alexrussell - 我刚刚在查看之后编辑了我的回答。 - stef
啊,这很有道理。我自己研究了调度程序,并找到了dispatchNow,我确实在我的控制台命令中使用了它,但我没有意识到我可以反转这种行为。谢谢你,这非常有帮助。 - alexrussell
我已经接受了@stefanzweifel的答案,因为它更贴近所问问题的答案(它们都是什么,5.0/5.1有什么区别),而且我在Slack上与他继续了一些讨论,并获得了更多的清晰度(或者至少有点“是的,这很令人困惑,不仅仅是你!”)。然而,你在这里对于5.0命令总线的解释对我的具体情况非常有帮助,如果我可以接受两个答案的话,我会的! - alexrussell
哈 - 是的,我有点偏离了实际问题! :) 很高兴我能帮忙! - stef
我正在寻找你的最后一段话,很高兴找到了它 :) - Alireza

22

我将那些“对象”看作是这样的:(我添加了一些来自我的一个副业项目的代码示例)

控制台(Console)

想要从命令行执行的事情(就像你提到的"删除x天前的文件"的例子一样)。但问题在于,你可以将其业务逻辑提取到一个命令(command)中。

示例:触发从 Imgur 获取图像的命令的控制台命令。类FetchImages包含获取图像的实际业务逻辑。

命令(Command)

包含实际逻辑的类。您还应该能够使用app()->make(Command::class)->handle()从应用程序调用此命令。

示例:在示例1中提到的命令。包含实际进行API调用并处理返回数据的逻辑。

任务(Jobs)

我用Laravel 5.0制作了这个应用程序,所以当时没有jobs这个东西。但就我所见,Jobs 就像是 Commands,但它们是排队的,并且可以分派。(正如你在那些示例中看到的那样,这些命令实现了你提到的SelfHandlingShouldBeQueued接口)。


我认为自己是一位经验丰富的 Laravel 开发人员,但是那些 CommandsJobs 的变化还是很难理解。

编辑: 来自 Laravel 文档:

app/Commands 目录已更名为 app/Jobs。但是,您不必将所有命令移动到新位置,您仍然可以使用 make:command 和 handler:command Artisan 命令来生成您的类。

同样地,app/Handlers 目录已更名为 app/Listeners 并且现在仅包含事件监听器。但是,您不需要移动或重命名现有的命令和事件处理程序,并且可以继续使用 handler:event 命令来生成事件处理程序。

通过为 Laravel 5.0 文件夹结构提供向后兼容性,您可以将应用程序升级到 Laravel 5.1,并在方便您或您的团队时缓慢升级其事件和命令到新位置。


2

在实际答案的基础上,还有一个补充。

Laravel 5.1及以上版本中的Jobs相当于Laravel 5.0中的Command Bus

这只是一种命名更改,因为Console\Commands(从控制台运行的命令)和应用程序任务中包含CommandsCommand Bus之间的混淆。

您不应该混淆:

  • Command Bus:用于“封装应用程序任务”(来自Laravel 5.0文档),现在已经更名为Jobs
  • Console\Commands:用于“Artisan[...] Laravel附带的命令行界面”(来自Laravel 5.1文档),自Laravel 4.x以来未更改

看起来很奇怪,5.1版本既有命令又有作业,并且它们作为两个独立的事物运作。 - alexrussell
我更新了我的答案,以更精确地说明“命令总线”不等于“控制台命令”。 - Ifnot
1
抱歉@Ifnot,我现在还不完全了解整个情况——有趣的是,命令被“重命名”为作业,但实际上在Laravel框架代码中并没有重命名:5.1确实有控制台命令,但它既有命令(如总线)又有作业(如“新”命令)。如果这只是一个简单的重命名,那么5.1就不会同时拥有命令和作业。无论如何,我知道这是为了向后兼容——Taylor希望5.0的用户能够轻松升级到5.1,因此保留了命令总线,但引入了作业作为命令的继承者。因此两者都可用。 - alexrussell
@alexrussell 是的,Command Bus 在5.0到5.1仍然保持兼容性以避免BC,但不再作为文档记录,因为Jobs应该替换该机制。 - Ifnot
的确 - 我认为我的最初困惑来自于命令在artisan中没有标记为弃用,也没有任何文档表明作业已经在5.1中取代了命令。 - alexrussell
我的困惑恰好相反 - 工作没有被标记为弃用,因为我们现在使用的是5.6版本。 - Dr. House

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接