How to sleep PHP(Laravel 5.2) in background

2020-06-23 10:07发布

问题:

I have created an artisan command that I want to run immediately after a method called. But the command contains a sleep(); command. I want to run that artisan command in background because the method need to return immediately response to user. My sample code is a below:

In route file

Route::get('test', function(){
    Artisan::queue('close:bidding', ['applicationId' => 1]);
    return 'called close:bidding';
});

In close:bidding command

public function handle()
    {
        $appId = $this->argument('applicationId');
        //following code line is making the problem
        sleep(1000 * 10);
        //close bidding after certain close time
        try{
            Application::where('id', $appId)->update(['live_bidding_status' => 'closed']);
        }catch (\PDOException $e){
            $this->info($e->getMessage());//test purpose
        }
        $this->info($appId.":  bid closed after 10 seconds of creation");
    } 

Problem When I hit /test url the return string called close:bidding is being shown after 10 seconds browser loading, because there is a sleep(10 * 1000) inside the command.

What I want I want to run the command in background. I mean when I hit the /test url it should immediately show up the called close:bidding but close:bidding command will be running in background. After 10 seconds it will update the application though the front-end user won't notice anything anything about it.

Partial Questions

  1. Is it somehow related to multi threading?

  2. Is it something that cannot be solve using PHP, should I think differently?

  3. Is there any way to solve this problem even using Laravel queue?

回答1:

Create a job

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

class JobTest implements ShouldQueue
{
    use InteractsWithQueue, Queueable, SerializesModels;

    private $payload = [];
    public function __construct($payload)
    {
        $this->payload = $payload;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        $appId = $this->payload('applicationId');
        //following code line is making the problem
        sleep(1000 * 10);
    }
}

To push job background queue

Route::get('test', function(){
    dispatch((new JobTest)->onQueue('queue_name'));
    return 'called close:bidding';
});

At this state we have job and you dispath the job to the queue. But it not processed yet. We need queue listener or worker to process those job in background

php artisan queue:listen --queue=queue_name --timeout=0  
OR
php artisan queue:work --queue=queue_name --timeout=0 //this will run forever

Note: May be you can try supervisord,beanstakd for manage queue

For more info refer this



回答2:

If you don't need all advantages of proper queue, which come at a price, it may be sufficient to use terminate middleware. It will do the job after response was sent to the browser.