当前位置:首页 > CMS教程 > 其它CMS > 列表

Laravel框架中队列和工作(Queues、Jobs)操作实例详解

发布:smiling 来源: PHP粉丝网  添加日期:2022-02-25 10:58:10 浏览: 评论:0 

在我们的web应用中,经常会遇到这样的情况:

用户在进行了某项操作后,我们需要在后台完成一个耗时且耗费资源的任务,以对应用户的操作。

通常来说,web应用中的操作都是同步的(synchronous),即用户的操作可以立即得到回馈。

但是在以上情况下,同步等待操作结果将是灾难性的。比如用户点击了申请密码重置邮件,倘若我们让用户一直停滞在等待页面,直至邮件发送成功,那么用户体验将非常地不好,因为有时候可能需要很长的时间才能将邮件发送完成。

从另一个角度来说,如果我们服务器处于高负荷的情况,当多个用户同时请求发送邮件等操作时,我们不希望同时地给服务器增加负荷,否则可能会导致服务器崩溃,造成无法预估的情况。

从以上的讨论可以看出,我们需要一种机制,可以非同步地响应用户操作,并且不会给服务器增加过大的负荷。

那么这样一种机制就是Queues和Jobs(即队列和工作)。

如果你系统地学习过计算机科学,那么队列的概念你应该不陌生。假设我们去银行办事,我们拿了一个号,发现前面有8个人在等待,那么我们实际上就处在一个队列之中,队列中靠前的人会先被叫到号码,并且叫号的顺序即拿号的顺序。这样的队列就叫做Queue,采用的是先到先处理的方式,不允许插队的情况存在。而我们要办的事情就叫Job。

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

打开config/queue.php,我们可以看到几种常见的队列设置:

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

在connections中,我们看到sync这个连接,sync是Laravel默认的队列,代表的就是synchronous,即同步队列。

今天我们要来看一下,如何使用database,即数据库来实现异步任务处理。

要使用database来作为队列的内部实现机制,我们需要建立一张用于储存Jobs的表:

$ php artisan queue:table     

$ php artisan migrate

以上命令将会在数据库创建名为jobs的表。

队列我们有了,那么现在我们来看一下Jobs,Laravel中jobs文件默认位置在app/Jobs文件夹下,我们可以通过make:job这个Artisan命令快速创建我们的job类:

$ php artisan make:job SendEmail

生成的job会实现Illuminate\Contracts\Queue\ShouldQueue这个接口,表明生成的job对象将被推到队列中进行异步处理。

job类其实很简单,里面只有一个名为handle的方法,该方法在job被queue处理的时候自动被调用。

在上面的命令中,我们创建了一个名为SendEmail的类:

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

可以看到,我们可以将model传递进job的constructor中。Laravel会自动序列化(Serialize)模型的识别信息,在job真正被处理的时候,完整的模型数据才会被从数据库调用出来。另外,在handle方法中,我们也可以注入我们的依赖dependencies。

好了,现在我们有了job类,可以创建job对象了,那么如何把job添加进队列呢?

在我们的控制器中,我们可以调用job的dispatch方法来将其添加进队列中:

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

这样一来,每当我们的控制器调用send方法时,就会创建一个SendEmail的job在数据库中。

那么怎么样调用Queue Worker来处理我们的jobs呢?

在.env文件中,我们将QUEUE_DRIVER=sync改为QUEUE_DRIVER=database。

接下来,我们运行以下Artisan命令:

$ php artisan queue:work

队列的worker会一直运行,每当有任务被添加进数据库jobs表中,worker便会自动抓取出任务进行处理。当任务失败时,worker会重复执行任务,直至最大尝试次数(默认为255)。我们可以手动设置最大尝试次数:

$ php artisan queue:work --tries=3

当然,我们也可以手动设置任务的超时(默认90s,在config/queue.php中的retry_after设置):

$ php artisan queue:work --timeout=30

最后,当没有任务的时候,我们可以设置一个睡眠时间,当worker在睡眠时间时,将不会处理任务:

$ php artisan queue:work --sleep=10

上面的命令意思是每当worker处理完所有任务后,会睡眠10s,然后才会再次检查任务队列。

Tags: Laravel队列 Queues Jobs

分享到: