【问题标题】:Laravel commands and jobsLaravel 命令和作业
【发布时间】:2015-11-12 17:36:00
【问题描述】:

我想知道 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 之间发生了什么,但有人告诉我,中间的那个(just 命令)基本上是不应该的不再使用——它们是从可排队作业在 5.0 中成为“命令”时开始使用的,但 Laravel 此后决定反对这一点,它们只是为了兼容性。但是,我不是 100% 在这一点上,所以澄清将不胜感激。

我的具体用例是我想要一个放置独立的“可运行”任务的地方。例如,将从给定目录中删除 5 天之前的文件(但它可以做任何事情)。

起初,这听起来像是一个控制台命令——我希望能够从artisan 运行它,首先。但我也可能希望它按计划进行(太好了,artisan schedule:run 运行控制台命令)。但我可能还想从代码异步执行它。控制台命令可以使用Artisan::call()同步运行,但对于异步,这是(我认为)队列进入的地方,它突然必须成为一项工作。

好的,我们有工作了。我们现在可以从代码中将它添加到队列中,但是我们如何将它作为工匠命令(同步)执行呢?我可以只创建一个瘦控制台命令并将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 commands and jobs

【问题讨论】:

    标签: laravel laravel-5 jobs laravel-5.1


    【解决方案1】:

    我看到那些“对象”是这样的:(我从我的一个业余项目中添加了一些代码示例)

    控制台

    我想从命令行执行的事情(正如您在示例中提到的“删除早于 x 的文件”)。但问题是,您可以将其业务逻辑提取为 command

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

    命令

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

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

    工作

    我使用 Laravel 5.0 制作了这个应用程序,所以 jobs 那时还不是什么东西。但正如我所看到的,作业就像命令,但它们是排队的并且可以被调度。 (正如您在这些示例中看到的那样,这些命令实现了您提到的接口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 中的作业是 Laravel 5.0 中的命令总线

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

      你不应该混淆:

      • Command Bus :用于“封装您的应用程序的任务”(来自 laravel 5.0 文档),现在重命名为 Jobs
      • Console\Commands :用于“Artisan [...] Laravel 中包含的命令行界面”(来自 laravel 5.1 文档),自 4.x 以来在 Laravel 中没有变化

      【讨论】:

      • 5.1 既有命令又有作业,而且它们作为两个独立的东西工作,这似乎很奇怪。
      • 我更新了我的答案以更精确地了解Command Bus != Console Commands
      • 抱歉@Ifnot,我现在明白了整个情况 - 有趣的是命令如何“重命名”为作业,但实际上并没有根据 Laravel 框架代码重命名:5.1 有控制台命令是的,但它有 both 命令(如在总线中) 作业(如在“新”命令中)。您可以想象,如果它只是一个简单的重命名,那么 5.1 将不会同时拥有命令和作业。无论如何,我理解这是出于 BC 的原因——Taylor 希望 5.0 人能够轻松升级到 5.1,所以保持原样的命令总线,但引入了作为命令继承者的工作。因此,两者都可用。
      • @alexrussell 是的,Command Bus 保持从 5.0 到 5.1 的兼容性以避免 BC,但不再记录,因为 Jobs 应该取代机制。
      • 确实 - 我认为我最初的困惑来自这样一个事实,即这些命令在 artisan 中没有被标记为已弃用,也没有任何文档表明作业在 5.1 中接管了命令。
      【解决方案3】:

      控制台命令

      Laravel 拥有控制台“命令”已有一段时间了。它们基本上没有变化,并且像往常一样工作。简单来说,它们相当于命令行的路由——应用程序的入口点。它们与...没有任何关系。

      命令总线

      Laravel 5.0 引入了Command Bus 模式的实现——命令总线命令。 (我相信这些被重命名为 Jobs 是因为它们与 CLI 命令之间的混淆)。

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

      处理程序

      在 laravel 中,您可以将作业声明为自处理 - 即它本身具有句柄方法。

      如果你想注册一个命令处理程序,你可以在服务提供者中调用如下:

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

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

      laravel 5.0 中的 handlers 目录是一种隐式声明这些关系的方式(即,commands 文件夹中的 EmailCommand 在 handlers 文件夹中会有一个 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 - 在仔细研究之后,我刚刚编辑了我的答案。
      • 嗯,有道理。我自己查看了调度程序,发现dispatchNow 确实在我的控制台命令中使用,但我没有意识到我可以反转这种行为。谢谢你,这很有帮助。
      • 仅供参考,我已接受@stefanzweifel 的回答,因为它更准确地回答了所提出的问题(它们都是什么以及与 5.0/5.1 有什么关系),我也确实在 Slack 中继续与他进行了一些讨论并且更加清晰(或者至少有点“是的,这很令人困惑,不仅仅是你!”)。但是,您在此处对 5.0 命令总线内容的解释对我的具体情况非常有帮助,如果我能同时接受,我会的!
      • 哈哈 - 是的。我确实有点偏离了实际问题! :) 很高兴我能帮上忙!
      猜你喜欢
      • 2020-09-09
      • 2019-01-27
      • 2019-10-14
      • 2015-08-26
      • 1970-01-01
      • 2015-04-19
      • 2020-06-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多