Laravel框架中隊(duì)列和工作(Queues、Jobs)操作實(shí)例詳解
在我們的web應(yīng)用中,經(jīng)常會遇到這樣的情況:
用戶在進(jìn)行了某項(xiàng)操作后,我們需要在后臺完成一個耗時(shí)且耗費(fèi)資源的任務(wù),以對應(yīng)用戶的操作。
通常來說,web應(yīng)用中的操作都是同步的(synchronous),即用戶的操作可以立即得到回饋。
但是在以上情況下,同步等待操作結(jié)果將是災(zāi)難性的。比如用戶點(diǎn)擊了申請密碼重置郵件,倘若我們讓用戶一直停滯在等待頁面,直至郵件發(fā)送成功,那么用戶體驗(yàn)將非常地不好,因?yàn)橛袝r(shí)候可能需要很長的時(shí)間才能將郵件發(fā)送完成。
從另一個角度來說,如果我們服務(wù)器處于高負(fù)荷的情況,當(dāng)多個用戶同時(shí)請求發(fā)送郵件等操作時(shí),我們不希望同時(shí)地給服務(wù)器增加負(fù)荷,否則可能會導(dǎo)致服務(wù)器崩潰,造成無法預(yù)估的情況。
從以上的討論可以看出,我們需要一種機(jī)制,可以非同步地響應(yīng)用戶操作,并且不會給服務(wù)器增加過大的負(fù)荷。
那么這樣一種機(jī)制就是Queues和Jobs(即隊(duì)列和工作)。
如果你系統(tǒng)地學(xué)習(xí)過計(jì)算機(jī)科學(xué),那么隊(duì)列的概念你應(yīng)該不陌生。假設(shè)我們?nèi)ャy行辦事,我們拿了一個號,發(fā)現(xiàn)前面有8個人在等待,那么我們實(shí)際上就處在一個隊(duì)列之中,隊(duì)列中靠前的人會先被叫到號碼,并且叫號的順序即拿號的順序。這樣的隊(duì)列就叫做Queue,采用的是先到先處理的方式,不允許插隊(duì)的情況存在。而我們要辦的事情就叫Job。
在Laravel中,我們可以很方便地使用Queues及Jobs來達(dá)到我們的目的。首先我們需要先來看一下,Laravel中有哪些Queues。
打開config/queue.php,我們可以看到幾種常見的隊(duì)列設(shè)置:
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默認(rèn)的隊(duì)列,代表的就是synchronous,即同步隊(duì)列。
今天我們要來看一下,如何使用database,即數(shù)據(jù)庫來實(shí)現(xiàn)異步任務(wù)處理。
要使用database來作為隊(duì)列的內(nèi)部實(shí)現(xiàn)機(jī)制,我們需要建立一張用于儲存Jobs的表:
$ php artisan queue:table $ php artisan migrate
以上命令將會在數(shù)據(jù)庫創(chuàng)建名為jobs的表。
隊(duì)列我們有了,那么現(xiàn)在我們來看一下Jobs。Laravel中jobs文件默認(rèn)位置在app/Jobs文件夾下,我們可以通過make:job這個Artisan命令快速創(chuàng)建我們的job類:
$ php artisan make:job SendEmail
生成的job會實(shí)現(xiàn)Illuminate\Contracts\Queue\ShouldQueue這個接口,表明生成的job對象將被推到隊(duì)列中進(jìn)行異步處理。
job類其實(shí)很簡單,里面只有一個名為handle的方法,該方法在job被queue處理的時(shí)候自動被調(diào)用。
在上面的命令中,我們創(chuàng)建了一個名為SendEmail的類:
<?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) // 這里我們可以處理我們的郵件并將郵件發(fā)送至接收人 } }
可以看到,我們可以將model傳遞進(jìn)job的constructor中。Laravel會自動序列化(Serialize)模型的識別信息,在job真正被處理的時(shí)候,完整的模型數(shù)據(jù)才會被從數(shù)據(jù)庫調(diào)用出來。另外,在handle方法中,我們也可以注入我們的依賴dependencies。
好了,現(xiàn)在我們有了job類,可以創(chuàng)建job對象了,那么如何把job添加進(jìn)隊(duì)列呢?
在我們的控制器中,我們可以調(diào)用job的dispatch方法來將其添加進(jìn)隊(duì)列中:
<?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信息并創(chuàng)建$email, Email是我們自定義的Model $email = Email::create($request->only('sender', 'to', 'content')); SendEmail::dispatch($email); } }
這樣一來,每當(dāng)我們的控制器調(diào)用send方法時(shí),就會創(chuàng)建一個SendEmail的job在數(shù)據(jù)庫中。
那么怎么樣調(diào)用Queue Worker來處理我們的jobs呢?
在.env文件中,我們將QUEUE_DRIVER=sync改為QUEUE_DRIVER=database。
接下來,我們運(yùn)行以下Artisan命令:
$ php artisan queue:work
隊(duì)列的worker會一直運(yùn)行,每當(dāng)有任務(wù)被添加進(jìn)數(shù)據(jù)庫jobs表中,worker便會自動抓取出任務(wù)進(jìn)行處理。當(dāng)任務(wù)失敗時(shí),worker會重復(fù)執(zhí)行任務(wù),直至最大嘗試次數(shù)(默認(rèn)為255)。我們可以手動設(shè)置最大嘗試次數(shù):
$ php artisan queue:work --tries=3
當(dāng)然,我們也可以手動設(shè)置任務(wù)的超時(shí)(默認(rèn)90s,在config/queue.php中的retry_after設(shè)置):
$ php artisan queue:work --timeout=30
最后,當(dāng)沒有任務(wù)的時(shí)候,我們可以設(shè)置一個睡眠時(shí)間,當(dāng)worker在睡眠時(shí)間時(shí),將不會處理任務(wù):
$ php artisan queue:work --sleep=10
上面的命令意思是每當(dāng)worker處理完所有任務(wù)后,會睡眠10s,然后才會再次檢查任務(wù)隊(duì)列
本文使用Laravel 5.6進(jìn)行講解
本文主要講解了Laravel框架中隊(duì)列和工作(Queues、Jobs)操作實(shí)例詳解,更多關(guān)于Laravel框架的使用技巧請查看下面的相關(guān)鏈接
相關(guān)文章
phpmyadmin中配置文件現(xiàn)在需要絕密的短語密碼的解決方法
phpmyadmin中配置文件現(xiàn)在需要絕密的短語密碼的解決方法...2007-02-02PHP依賴注入(DI)和控制反轉(zhuǎn)(IoC)詳解
這篇文章主要介紹了PHP依賴注入(DI)和控制反轉(zhuǎn)(IoC)的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06php實(shí)現(xiàn)在服務(wù)器端調(diào)整圖片大小的方法
這篇文章主要介紹了php實(shí)現(xiàn)在服務(wù)器端調(diào)整圖片大小的方法,實(shí)例分析了imageResizer與loadimage操作圖片的相關(guān)技巧,需要的朋友可以參考下2015-06-06PHP實(shí)現(xiàn)PDO的mysql數(shù)據(jù)庫操作類
這篇文章主要介紹了PHP實(shí)現(xiàn)PDO的mysql數(shù)據(jù)庫操作類,其中dbconfig類負(fù)責(zé)配置數(shù)據(jù)庫訪問信息,dbtemplate類集合了對數(shù)據(jù)庫的訪問操作,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2014-12-12實(shí)例探索PHP只讀屬性改變游戲規(guī)則的特性
這篇文章主要為大家介紹了PHP只讀屬性改變游戲規(guī)則的特性實(shí)例探索,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01