2017-03-04 40 views
3

我需要一种异步运行某些任务的方法,因为每个任务之间的执行时间不尽相同,我希望以使用Laravel Jobs和数据库作为驱动程序的异步方式运行。Laravel Jobs不是异步的

我创建使用命令行来测试工作: PHP工匠制作:工作TestOne PHP工匠制作:工作TestTwo

TestOne.php

<?php 

namespace App\Jobs; 

use App\Jobs\Job; 
use Illuminate\Queue\SerializesModels; 
use Illuminate\Queue\InteractsWithQueue; 
use Illuminate\Contracts\Queue\ShouldQueue; 

class TestOne extends Job implements ShouldQueue 
{ 
    use InteractsWithQueue, SerializesModels; 

    /** 
    * Create a new job instance. 
    * 
    * @return void 
    */ 
    public function __construct() 
    { 
     // 
    } 

    /** 
    * Execute the job. 
    * 
    * @return void 
    */ 
    public function handle() 
    { 
     sleep(5); 
     foreach (range(1, 10) as $item) 
      \Log::info("TestOne: item #" . $item); 
    } 
} 

TestTwo.php

<?php 

namespace App\Jobs; 

use App\Jobs\Job; 
use Illuminate\Queue\SerializesModels; 
use Illuminate\Queue\InteractsWithQueue; 
use Illuminate\Contracts\Queue\ShouldQueue; 

class TestTwo extends Job implements ShouldQueue 
{ 
    use InteractsWithQueue, SerializesModels; 

    /** 
    * Create a new job instance. 
    * 
    * @return void 
    */ 
    public function __construct() 
    { 
     // 
    } 

    /** 
    * Execute the job. 
    * 
    * @return void 
    */ 
    public function handle() 
    { 
     foreach (range(1, 10) as $item) 
      \Log::info("TestTwo: item #" . $item); 
    } 
} 

我只是在laravel的日志文件中记录了一些消息,并且由于TestOne正在休眠5秒,TestTwo应该首先记录消息

HomeController.php

<?php 

namespace App\Http\Controllers; 

use Queue; 
use App\Jobs\TestOne; 
use App\Jobs\TestTwo; 

class HomeController extends Controller 
{ 
    public function index() 
    { 
     $this->dispatch(new TestOne()); 
     $this->dispatch(new TestTwo()); 
     die("stop"); 
    } 
} 

然而TestTwo工作仍然等待TestOne作业完成:

[2017-03-04 17:00:30] local.INFO: TestOne: item #1 
[2017-03-04 17:00:30] local.INFO: TestOne: item #2 
[2017-03-04 17:00:30] local.INFO: TestOne: item #3 
[2017-03-04 17:00:30] local.INFO: TestOne: item #4 
[2017-03-04 17:00:30] local.INFO: TestOne: item #5 
[2017-03-04 17:00:30] local.INFO: TestOne: item #6 
[2017-03-04 17:00:30] local.INFO: TestOne: item #7 
[2017-03-04 17:00:30] local.INFO: TestOne: item #8 
[2017-03-04 17:00:30] local.INFO: TestOne: item #9 
[2017-03-04 17:00:30] local.INFO: TestOne: item #10 
[2017-03-04 17:00:30] local.INFO: TestTwo: item #1 
[2017-03-04 17:00:30] local.INFO: TestTwo: item #2 
[2017-03-04 17:00:30] local.INFO: TestTwo: item #3 
[2017-03-04 17:00:30] local.INFO: TestTwo: item #4 
[2017-03-04 17:00:30] local.INFO: TestTwo: item #5 
[2017-03-04 17:00:30] local.INFO: TestTwo: item #6 
[2017-03-04 17:00:30] local.INFO: TestTwo: item #7 
[2017-03-04 17:00:30] local.INFO: TestTwo: item #8 
[2017-03-04 17:00:30] local.INFO: TestTwo: item #9 
[2017-03-04 17:00:30] local.INFO: TestTwo: item #10 

我与php artisan queue:listen

运行的作业我在做什么错在这里?我真的需要这些任务异步运行,就像说,一个JS AJAX请求会起作用。

我正在使用Laravel 5.2。再次,我使用“数据库”作为队列驱动程序,是的,我已经迁移了作业表。使用数据库作为驱动程序是不可能的?

回答

4

要并行处理作业,您必须按@dparoli指出的将其拆分到不同的队列中。

这样,您不仅可以对它们进行分类,还可以优先考虑队列工作人员将如何处理它们。

当分派工作,你指定什么排队它属于:

$this->dispatch((new TestOne())->onQueue('queue1')); 
$this->dispatch((new TestTwo())->onQueue('queue2')); 

这种方式可以产生多个队列工作者分别处理工作:

php artisan queue:work --queue=queue1 
php artisan queue:work --queue=queue2 

您也可以使用单一队列工作者优先处理队列的方式,所以你可以给予某些工作高于或低于其他工作的优先级:

php artisan queue:work --queue=queue2,queue1 

通过使用像Supervisor这样的进程监视器,您甚至可以在多个进程中产生一个单独的worker,如detailed in the documentation

值得注意的是,优先考虑其队列的单个队列工作者仍然会通过除给定队列优先级之外的FIFO优先级来处理他们的工作。为了获得更好的并行性,你需要产生多个队列工作者。

这适用于所有队列驱动程序。

1

异步表示作业不会执行控制器方法。例如,如果您将sleep(5);添加到One并且将sleep(10);添加到Two,则die('stop');仍然会在您请求控制器时立即发生。在执行Synchronous时,达到die需要15秒。

队列 FIFO的概念(先入先出)的种类。当你去超市时,如果你有更多的物品(处理时间太多)比第二人没有关系,如果你是第一人,第二人将不得不等待你完成。这就是Queue的工作原理。

为了达到你想要的,我建议一个简单的测试练习。

  • 停止queue:listen
  • 呼叫控制器(导致被排队两个作业);
  • 拨打电话php artisan queue:work &从终端
  • 按向上箭头,并再次发出命令真正快。

由于&会将过程发送到后台,您可以几乎瞬间发送两次queue:work。这应该带来你期望的行为。

这是我的输出

[03:01 PM]-[[email protected]]-[/var/www/html/jobs] 
php artisan queue:work & 
[1] 2456 

[03:02 PM]-[[email protected]]-[/var/www/html/jobs] 
php artisan queue:work & 
[2] 2458 

[03:02 PM]-[[email protected]]-[/var/www/html/jobs] 
[2017-03-04 18:02:33] Processed: App\Jobs\TaskTwo 
[2017-03-04 18:02:37] Processed: App\Jobs\TaskOne 

我想说明的一点是:

  • 控制器将不必等待作业完成(这是异步表示)
  • queue:listen将一次运行一个作业,并且只会在第一个完成后才开始下一个作业;
  • queue:work将开始排队的第一份工作,并将其标记为保留(列reserved_at),以便下一个queue:work可以采取未保留的下一份工作。在不同的队列,
+0

感谢您的回答。好的,如果Asynchronous在这种情况下是错误的术语,那么你会怎么称呼它?如何在实际应用程序中使用'queue:work'?我还使用队列发送电子邮件,因为我的应用程序严重依赖发送电子邮件。 –

+0

你的控制器是异步的,你的队列不是。你为什么需要异步队列?你可能不会。 –

2

推工作即队列1,队列2等

对于您所定义的,你应该有一个工人每个队列:

php artisan queue:work --queue=queue1 
php artisan queue:work --queue=queue2 

您可以使用supervisord监测队列工人每个文档。

使用此解决方案,每个队列都运行异步方面尊重其他队列,但同一队列中的两个作业不是异步,它们尊重FIFO优先级。