douwei1921 2017-03-04 17:31
浏览 278
已采纳

Laravel Jobs不是异步的

I need a way to run some tasks asynchronously as the execution time varies between each task and I want to run the in an asynchronous way using Laravel Jobs and database as the driver.

I created to test jobs using the command line: php artisan make:job TestOne php artisan make:job 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);
    }
}

I simply log some messages in laravel's log file, and since TestOne is sleeping for 5 seconds, TestTwo should log the messages first

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");
    }
}

However TestTwo job still waits until TestOne job is done:

[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 

I am running the jobs with php artisan queue:listen

What am I doing wrong here? I really need these tasks to run asynchronously, just like, say, a JS AJAX request would work like.

I am using Laravel 5.2. Again, I am using "database" as the queue driver and yes I have migrated the jobs table. Is it not possible using the database as the driver?

  • 写回答

3条回答 默认 最新

  • douzaipou3327 2017-03-04 18:42
    关注

    To process jobs in parallel you'd have to split them across different queues as @dparoli pointed out.

    This way you can not only categorize them but also priorize how they'll be processed by your queue workers.

    When dispatching a job, you'll specify what queue it belongs:

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

    That way you can spawn multiple queue workers to process jobs separately:

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

    You can also use a single queue worker which priorize how queues are processed, so you can give a higher or lower precedence for some jobs over others:

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

    By using a process monitor like Supervisor you can even spawn a single worker in multiple processes as detailed in the documentation.

    It's worth noting that a single queue worker which prioritizes its queues will still process their jobs by taking the FIFO precedence in addition to the given queue priority. To achieve a better parallelism you'll want to spawn multiple queue workers.

    This holds true for all queue drivers.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 想问一下stata17中这段代码哪里有问题呀
  • ¥15 flink cdc无法实时同步mysql数据
  • ¥100 有人会搭建GPT-J-6B框架吗?有偿
  • ¥15 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决