Laravel框架中隊列和工作(Queues、Jobs)操作實例詳解


 

 更新時間:2020年04月06日 14:51:05   作者:Eagle L.  
 
這篇文章主要介紹了Laravel框架中隊列和工作(Queues、Jobs)操作實例詳解,需要的朋友可以參考下

在我們的web應用中,經常會遇到這樣的情況:

用戶在進行了某項操作后,我們需要在后台完成一個耗時且耗費資源的任務,以對應用戶的操作。

通常來說,web應用中的操作都是同步的(synchronous),即用戶的操作可以立即得到回饋。

但是在以上情況下,同步等待操作結果將是災難性的。比如用戶點擊了申請密碼重置郵件,倘若我們讓用戶一直停滯在等待頁面,直至郵件發送成功,那么用戶體驗將非常地不好,因為有時候可能需要很長的時間才能將郵件發送完成。

從另一個角度來說,如果我們服務器處於高負荷的情況,當多個用戶同時請求發送郵件等操作時,我們不希望同時地給服務器增加負荷,否則可能會導致服務器崩潰,造成無法預估的情況。

從以上的討論可以看出,我們需要一種機制,可以非同步地響應用戶操作,並且不會給服務器增加過大的負荷。

那么這樣一種機制就是Queues和Jobs(即隊列和工作)。

如果你系統地學習過計算機科學,那么隊列的概念你應該不陌生。假設我們去銀行辦事,我們拿了一個號,發現前面有8個人在等待,那么我們實際上就處在一個隊列之中,隊列中靠前的人會先被叫到號碼,並且叫號的順序即拿號的順序。這樣的隊列就叫做Queue,采用的是先到先處理的方式,不允許插隊的情況存在。而我們要辦的事情就叫Job。

在Laravel中,我們可以很方便地使用Queues及Jobs來達到我們的目的。首先我們需要先來看一下,Laravel中有哪些Queues。

打開config/queue.php,我們可以看到幾種常見的隊列設置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
return [     
   
   /*     
   |--------------------------------------------------------------------------     
   | Default Queue Connection Name     
   |--------------------------------------------------------------------------     
   |     
   | Laravel's queue API supports an assortment of back-ends via a single     
   | API, giving you convenient access to each back-end using the same     
   | syntax for every one. Here you may define a default connection.     
   |     
   */     
   
   'default' => env( 'QUEUE_DRIVER' , 'sync' ),     
   
   /*     
   |--------------------------------------------------------------------------     
   | Queue Connections     
   |--------------------------------------------------------------------------     
   |     
   | Here you may configure the connection information for each server that     
   | is used by your application. A default configuration has been added     
   | for each back-end shipped with Laravel. You are free to add more.     
   |     
   | Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null"     
   |     
   */     
   
   'connections' => [     
   
     'sync' => [     
       'driver' => 'sync' ,     
     ],     
   
     'database' => [     
       'driver' => 'database' ,     
       'table' => 'jobs' ,     
       'queue' => 'default' ,     
       'retry_after' => 90,     
     ],     
   
     'beanstalkd' => [     
       'driver' => 'beanstalkd' ,     
       'host' => 'localhost' ,     
       'queue' => 'default' ,     
       'retry_after' => 90,     
     ],     
   
     'sqs' => [     
       'driver' => 'sqs' ,     
       'key' => env( 'SQS_KEY' , 'your-public-key' ),     
       'secret' => env( 'SQS_SECRET' , 'your-secret-key' ),     
       'prefix' => env( 'SQS_PREFIX' , 'https://sqs.us-east-1.amazonaws.com/your-account-id' ),     
       'queue' => env( 'SQS_QUEUE' , 'your-queue-name' ),     
       'region' => env( 'SQS_REGION' , 'us-east-1' ),     
     ],     
   
     'redis' => [     
       'driver' => 'redis' ,     
       'connection' => 'default' ,     
       'queue' => 'default' ,     
       'retry_after' => 90,     
       'block_for' => null,     
     ],     
   
   ],     
   
   /*     
   |--------------------------------------------------------------------------     
   | Failed Queue Jobs     
   |--------------------------------------------------------------------------     
   |     
   | These options configure the behavior of failed queue job logging so you     
   | can control which database and table are used to store the jobs that     
   | have failed. You may change them to any database / table you wish.     
   |     
   */     
   
   'failed' => [     
     'database' => env( 'DB_CONNECTION' , 'mysql' ),     
     'table' => 'failed_jobs' ,     
   ],     
   
];

在connections中,我們看到sync這個連接。sync是Laravel默認的隊列,代表的就是synchronous,即同步隊列。

今天我們要來看一下,如何使用database,即數據庫來實現異步任務處理。

要使用database來作為隊列的內部實現機制,我們需要建立一張用於儲存Jobs的表:

1
2
$ php artisan queue:table    
$ php artisan migrate

以上命令將會在數據庫創建名為jobs的表。

隊列我們有了,那么現在我們來看一下Jobs。Laravel中jobs文件默認位置在app/Jobs文件夾下,我們可以通過make:job這個Artisan命令快速創建我們的job類:

1
$ php artisan make :job SendEmail

生成的job會實現Illuminate\Contracts\Queue\ShouldQueue這個接口,表明生成的job對象將被推到隊列中進行異步處理。

job類其實很簡單,里面只有一個名為handle的方法,該方法在job被queue處理的時候自動被調用。

在上面的命令中,我們創建了一個名為SendEmail的類:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php   
   
namespace App\Jobs;   
   
use App\Email;   
use Illuminate\Bus\Queueable;   
use Illuminate\Queue\SerializesModels;   
use Illuminate\Queue\InteractsWithQueue;   
use Illuminate\Contracts\Queue\ShouldQueue;   
use Illuminate\Foundation\Bus\Dispatchable;   
   
class SendEmail implements ShouldQueue   
{   
   use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;   
   
   protected $email ;   
   
   /**   
    * Create a new job instance.   
    *   
    * @param Podcast $podcast   
    * @return void   
    */   
   public function __construct(Email $email )   
   {   
     $this ->email = $email ;   
   }   
   
   /**   
    * Execute the job.   
    *   
    * @param AudioProcessor $processor   
    * @return void   
    */   
   public function handle()   
   {   
     // Process email and send the email to recipient(s)   
     // 這里我們可以處理我們的郵件並將郵件發送至接收人
   }   
}

可以看到,我們可以將model傳遞進job的constructor中。Laravel會自動序列化(Serialize)模型的識別信息,在job真正被處理的時候,完整的模型數據才會被從數據庫調用出來。另外,在handle方法中,我們也可以注入我們的依賴dependencies。

好了,現在我們有了job類,可以創建job對象了,那么如何把job添加進隊列呢?

在我們的控制器中,我們可以調用job的dispatch方法來將其添加進隊列中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php 
   
namespace App\Http\Controllers; 
   
use App\Jobs\SendEmail; 
use Illuminate\Http\Request; 
use App\Http\Controllers\Controller; 
use App\Email;
   
class EmailsController extends Controller 
   /** 
    * Store a new email. 
   
    * @param Request $request 
    * @return Response 
    */ 
   public function send(Request $request
  
     // Create email... 
     // 這里我們提取email信息並創建$email, Email是我們自定義的Model
     $email = Email::create( $request ->only( 'sender' , 'to' , 'content' ));
   
     SendEmail::dispatch( $email ); 
  
}

這樣一來,每當我們的控制器調用send方法時,就會創建一個SendEmail的job在數據庫中。

那么怎么樣調用Queue Worker來處理我們的jobs呢?

在.env文件中,我們將QUEUE_DRIVER=sync改為QUEUE_DRIVER=database。

接下來,我們運行以下Artisan命令:

1
$ php artisan queue:work

隊列的worker會一直運行,每當有任務被添加進數據庫jobs表中,worker便會自動抓取出任務進行處理。當任務失敗時,worker會重復執行任務,直至最大嘗試次數(默認為255)。我們可以手動設置最大嘗試次數:

1
$ php artisan queue:work --tries=3

當然,我們也可以手動設置任務的超時(默認90s,在config/queue.php中的retry_after設置):

1
$ php artisan queue:work --timeout=30

最后,當沒有任務的時候,我們可以設置一個睡眠時間,當worker在睡眠時間時,將不會處理任務:

1
$ php artisan queue:work -- sleep =10

上面的命令意思是每當worker處理完所有任務后,會睡眠10s,然后才會再次檢查任務隊列

本文使用Laravel 5.6進行講解

本文主要講解了Laravel框架中隊列和工作(Queues、Jobs)操作實例詳解,更多關於Laravel框架的使用技巧請查看下面的相關鏈接


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM