2016-09-07 117 views
0

目前我正在開發一個項目,在該項目中排隊發送電子郵件。但是我不知道運行隊列監聽器的「最佳方式」是什麼。現在我只知道nohup的方式。運行Laravel隊列的「最佳方式」監聽

但是,通過使用nohup,感覺像隊列偵聽器不再是應用程序的一部分。這就像使用調度程序使您的cronjob成爲應用程序的更多部分。

有沒有其他的方法來聽隊列,你會喜歡什麼?

+0

我通過編寫我計劃每分鐘運行一次的進程偵聽器類型任務來實現此目的。所做的是檢查隊列是否正在使用'pgrep'運行,並在發現它未運行時啓動它。 – Jonathon

+0

@Jonathon像cronjob一樣的任務?我在我的腦海中也有這個想法,在我的laravel時間表中添加'queue:listen'來每天運行,但添加'withoutOverlapping()'。它希望看看:'$ schedule-> command('queue:listen') - > daily() - > withoutOverlapping();'。 –

+1

是的,我創建了控制檯命令'App \ Console \ Commands \ QueueProcessListener'。然後我將它添加到'Kernel.php'中以使其可用於Artisan,並且我最終將它添加到內核的'schedule'方法中以使其每5分鐘運行一次:'$ schedule-> command('queue-process-聽衆') - > everyFiveMinutes();' – Jonathon

回答

3

這裏是我寫來實現:

應用程序/控制檯/命令/ QueueProcessListener.php

<?php 

namespace App\Console\Commands; 

use Illuminate\Console\Command; 

class QueueProcessListener extends Command 
{ 
    /** 
    * The name of the command/process we want to monitor. This string will be used both to check to see if the process 
    * is currently running and to spawn it (The arguments are appended to it). 
    * 
    * @var string 
    */ 
    protected $command = 'php artisan queue:listen'; 

    /** 
    * The arguments to pass to the process when spawning it. 
    * 
    * @var string 
    */ 
    protected $arguments = '--tries=3'; 

    /** 
    * The signature of the console command. We use the signature when running it through Artisan: php artisan $signature 
    * 
    * @var string 
    */ 
    protected $signature = 'queue-process-listener'; 

    /** 
    * The console command description. 
    * 
    * @var string 
    */ 
    protected $description = 'Monitor the queue listener process to ensure it is always running.'; 

    /** 
    * Create a new command instance. 
    */ 
    public function __construct() 
    { 
     parent::__construct(); 
    } 

    /** 
    * Execute the console command. 
    * 
    * @return mixed 
    */ 
    public function handle() 
    { 
     if (!$this->isProcessRunning($this->command)) { 
      $this->info("Starting queue listener."); 
      $this->executeShellCommand($this->command, $this->arguments, true); 
     } else { 
      $this->info("Queue listener is running."); 
     } 
    } 

    /** 
    * Execute a shell command, with the provided arguments, and optionally in the background. Commands that are not run 
    * in the background will return their output/response. 
    * 
    * @param $command 
    * @param string $arguments 
    * @param bool $background 
    * @return string 
    */ 
    public function executeShellCommand($command, $arguments = '', $background = false) 
    { 
     $command = trim($command); 
     if (!is_string($command) || empty($command)) { 
      return null; 
     } 

     $arguments = trim($arguments); 

     $cmd = trim($command . ' ' . $arguments) . ($background ? ' > /dev/null 2>/dev/null &' : ''); 
     return shell_exec($cmd); 
    } 

    /** 
    * Check if a process is running using pgrep. 
    * 
    * @param $process 
    * @return bool 
    */ 
    public function isProcessRunning($process) 
    { 
     $output = $this->executeShellCommand('pgrep -f "' . $process . '"'); 

     return !empty(trim($output)); 
    } 
} 

應用程序/軟件/ Kernel.php

<?php 

namespace App\Console; 

use Illuminate\Console\Scheduling\Schedule; 
use Illuminate\Foundation\Console\Kernel as ConsoleKernel; 

class Kernel extends ConsoleKernel 
{ 
    /** 
    * The Artisan commands provided by your application. 
    * 
    * @var array 
    */ 
    protected $commands = [ 
     Commands\QueueProcessListener::class 
    ]; 

    /** 
    * Define the application's command schedule. 
    * 
    * @param \Illuminate\Console\Scheduling\Schedule $schedule 
    * @return void 
    */ 
    protected function schedule(Schedule $schedule) 
    { 
     // Schedule my process listener to run every 5 minutes. 
     $schedule->command('queue-process-listener')->everyFiveMinutes(); 
    } 
} 
+0

謝謝,我想我會像你說的那樣去做。不是'$ schedule->命令('queue:listen') - > daily() - > withoutOverlapp ing()'不夠嗎?由於它已經是一個可以被調用和執行的命令。 –

+0

很酷。這樣做的問題是,如果隊列偵聽器由於某種原因在一天中停止,則直到第二天才會再次啓動隊列偵聽器。另一方面,如果白天不停止,你可能會冒着運行多個隊列監聽器的風險(如果你使用'nohup'或'&'在後臺啓動命令等)。如果直接運行'queue:listen'命令,它不會及時執行,讓其他命令也可以運行 - 這樣可以有效地阻止調度程序。 – Jonathon

+0

感謝您的回覆。忘記'daily()'或'everyMinute()'。通過使用'withoutOverlapp ing()',可以防止它在運行時被執行,對嗎?或者你是否說即使在之前完成之後使用'withoutOverlapp ing()'執行,調度器也會對這些命令進行排隊/堆棧?還有,你是說調度程序不是異步的(它不能一次執行多個)? –

0

文檔告訴你如何實現這一點: https://laravel.com/docs/5.3/queues#supervisor-configuration

我不確定你的意思是不是「應用程序的一部分」。 Crons和後臺工作進程是任何規模服務器體系結構的標準部分。使用它們沒有任何問題。

你也應該真的避免做Jonathon的回答建議,這基本上是用php編寫你自己的supervisord。如果你的服務器重新啓動會怎樣已經有針對這個問題的經過測試的解決方案,現在已經由linux社區開發和支持了很長時間 - 您應該真的使用它們。