搜索
首页后端开发php教程[ Laravel 5.2 文档 ] 服务 -- 队列

1、简介

Laravel队列服务为各种不同的后台队列提供了统一的API。队列允许你推迟耗时任务(例如发送邮件)的执行,从而大幅提高web请求速度。

1.1 配置

队列配置文件存放在 config/queue.php。在该文件中你将会找到框架自带的每一个队列驱动的连接配置,包括数据库、 Beanstalkd、  IronMQ、  Amazon SQS、  Redis以及同步(本地使用)驱动。其中还包含了一个null队列驱动以拒绝队列任务。

1.2 队列驱动预备知识

数据库

为了使用 database队列驱动,需要一张数据库表来存放任务,要生成创建该表的迁移,运行Artisan命令 queue:table,迁移被创建好了之后,使用 migrate命令运行迁移:

php artisan queue:tablephp artisan migrate

其它队列依赖

下面是以上列出队列驱动需要安装的依赖:

  • Amazon SQS:  aws/aws-sdk-php ~3.0
  • Beanstalkd:  pda/pheanstalk ~3.0
  • Redis:  predis/predis ~1.0

2、编写任务类

2.1 生成任务类

默认情况下,应用的所有队列任务都存放在 app/Jobs目录。你可以使用Artisan CLI生成新的队列任务:

php artisan make:job SendReminderEmail

该命令将会在 app/Jobs目录下生成一个新的类,并且该类实现了 Illuminate\Contracts\Queue\ShouldQueue接口,告诉Laravel该任务应该被推送到队列而不是同步运行。

2.2 任务类结构

任务类非常简单,正常情况下只包含一个当队列处理该任务时被执行的 handle方法,让我们看一个任务类的例子:

<?phpnamespace App\Jobs;use App\User;use App\Jobs\Job;use Illuminate\Contracts\Mail\Mailer;use Illuminate\Queue\SerializesModels;use Illuminate\Queue\InteractsWithQueue;use Illuminate\Contracts\Queue\ShouldQueue;class SendReminderEmail extends Job implements ShouldQueue{    use InteractsWithQueue, SerializesModels;    protected $user;    /**     * 创建一个新的任务实例     *     * @param  User  $user     * @return void     */    public function __construct(User $user)    {        $this->user = $user;    }    /**     * 执行任务     *     * @param  Mailer  $mailer     * @return void     */    public function handle(Mailer $mailer)    {        $mailer->send('emails.reminder', ['user' => $this->user], function ($m) {            //        });        $this->user->reminders()->create(...);    }}

在本例中,注意我们能够直接将Eloquent模型传递到对列任务的构造函数中。由于该任务使用了 SerializesModelstrait,Eloquent模型将会在任务被执行是优雅地序列化和反序列化。如果你的队列任务在构造函数中接收Eloquent模型,只有模型的主键会被序列化到队列,当任务真正被执行的时候,队列系统会自动从数据库中获取整个模型实例。这对应用而言是完全透明的,从而避免序列化整个Eloquent模型实例引起的问题。

handle方法在任务被队列处理的时候被调用,注意我们可以在任务的 handle方法中进行依赖注入。Laravel服务容器会自动注入这些依赖。

出错

如果任务被处理的时候抛出异常,则该任务将会被自动释放回队列以便再次尝试执行。任务会持续被释放知道尝试次数达到应用允许的最大次数。最大尝试次数通过Artisan任务 queue:listen或 queue:work上的 --tries开关来定义。关于运行队列监听器的更多信息可以在下面看到。

手动释放任务

如果你想要手动释放任务,生成的任务类中自带的 InteractsWithQueuetrait提供了释放队列任务的 release方法,该方法接收一个参数——同一个任务两次运行之间的等待时间:

public function handle(Mailer $mailer){    if (condition) {        $this->release(10);    }}

检查尝试运行次数

正如上面提到的,如果在任务处理期间发生异常,任务会自动释放回队列中,你可以通过 attempts方法来检查该任务已经尝试运行次数:

public function handle(Mailer $mailer){    if ($this->attempts() > 3) {        //    }}

3、推送任务到队列

默认的 Laravel 控制器位于 app/Http/Controllers/Controller.php并使用了 DispatchesJobstrait。该trait提供了一些允许你方便推送任务到队列的方法,例如 dispatch方法:

<?phpnamespace App\Http\Controllers;use App\User;use Illuminate\Http\Request;use App\Jobs\SendReminderEmail;use App\Http\Controllers\Controller;class UserController extends Controller{    /**     * 发送提醒邮件到指定用户     *     * @param  Request  $request     * @param  int  $id     * @return Response     */    public function sendReminderEmail(Request $request, $id)    {        $user = User::findOrFail($id);        $this->dispatch(new SendReminderEmail($user));    }}

DispatchesJobs Trait

当然,有时候你想要从应用中路由或控制器之外的某些地方分发任务,因为这个原因,你可以在应用的任何类中包含 DispatchesJobstrait,从而获取对分发方法的访问,举个例子,下面是使用该trait的示例类:

<?phpnamespace App;use Illuminate\Foundation\Bus\DispatchesJobs;class ExampleClass{    use DispatchesJobs;}

dispatch方法

或者,你也可以使用全局的dispatch方法:

Route::get('/job', function () {    dispatch(new App\Jobs\PerformTask);    return 'Done!';});

为任务指定队列

你还可以指定任务被发送到的队列。

根据任务被推送到的不同队列,你可以对队列任务进行“分类”,甚至优先考虑分配给多个队列的worker数目。这并不会如队列配置文件中定义的那样将任务推送到不同队列“连接”,而只是在单个连接中发送给特定队列。要指定该队列,使用任务实例上的 onQueue方法,该方法由 Laravel 自带的基类 App\Jobs\Job中的  Illuminate\Bus\Queueabletrait提供:

<?phpnamespace App\Http\Controllers;use App\User;use Illuminate\Http\Request;use App\Jobs\SendReminderEmail;use App\Http\Controllers\Controller;class UserController extends Controller{    /**     * 发送提醒邮件到指定用户     *     * @param  Request  $request     * @param  int  $id     * @return Response     */    public function sendReminderEmail(Request $request, $id)    {        $user = User::findOrFail($id);        $job = (new SendReminderEmail($user))->onQueue('emails');        $this->dispatch($job);    }}

3.1 延迟任务

有时候你可能想要延迟队列任务的执行。例如,你可能想要将一个注册15分钟后给消费者发送提醒邮件的任务放到队列中,可以通过使用任务类上的 delay方法来实现,该方法由 Illuminate\Bus\Queueabletrait提供:

<?phpnamespace App\Http\Controllers;use App\User;use Illuminate\Http\Request;use App\Jobs\SendReminderEmail;use App\Http\Controllers\Controller;class UserController extends Controller{    /**     * 发送提醒邮件到指定用户     *     * @param  Request  $request     * @param  int  $id     * @return Response     */    public function sendReminderEmail(Request $request, $id)    {        $user = User::findOrFail($id);        $job = (new SendReminderEmail($user))->delay(60);        $this->dispatch($job);    }}

在本例中,我们指定任务在队列中开始执行前延迟60秒。

注意:Amazon SQS服务最大延迟时间是15分钟。

3.2 任务事件

任务完成事件

Queue::after方法允许你在队列任务执行成功后注册一个要执行的回调函数。在该回调中我们可以添加日志、统计数据。例如,我们可以在Laravel内置的 AppServiceProvider中添加事件回调:

<?phpnamespace App\Providers;use Queue;use Illuminate\Support\ServiceProvider;class AppServiceProvider extends ServiceProvider{    /**     * Bootstrap any application services.     *     * @return void     */    public function boot()    {        Queue::after(function ($connection, $job, $data) {            //        });    }    /**     * Register the service provider.     *     * @return void     */    public function register()    {        //    }}

4、运行队列监听器

启动任务监听器

Laravel 包含了一个 Artisan 命令用来运行被推送到队列的新任务。你可以使用 queue:listen命令运行监听器:

php artisan queue:listen

还可以指定监听器使用哪个队列连接:

php artisan queue:listen connection

注意一旦任务开始后,将会持续运行直到手动停止。你可以使用一个过程监视器如Supervisor来确保队列监听器没有停止运行。

队列 优先级

你可以传递逗号分隔的队列连接列表到 listen任务来设置队列优先级:

php artisan queue:listen --queue=high,low

在本例中, high队列上的任务总是在从 low队列移动任务之前被处理。

指定任务超时参数

你还可以设置每个任务允许运行的最大时间(以秒为单位):

php artisan queue:listen --timeout=60

指定队列睡眠时间

此外,可以指定轮询新任务之前的等待时间(以秒为单位):

php artisan queue:listen --sleep=5

需要注意的是队列只会在队列上没有任务时“睡眠”,如果存在多个有效任务,该队列会持续运行,从不睡眠。

4.1 Supervisor配置

Supervisor为Linux操作系统提供的进程监视器,将会在失败时自动重启 queue:listen或 queue:work命令,要在Ubuntu上安装Supervisor,使用如下命令:

sudo apt-get install supervisor

Supervisor配置文件通常存放在 /etc/supervisor/conf.d目录,在该目录中,可以创建多个配置文件指示Supervisor如何监视进程,例如,让我们创建一个开启并监视 queue:work进程的 laravel-worker.conf文件:

[program:laravel-worker]process_name=%(program_name)s_%(process_num)02dcommand=php /home/forge/app.com/artisan queue:work sqs --sleep=3 --tries=3 --daemonautostart=trueautorestart=trueuser=forgenumprocs=8redirect_stderr=truestdout_logfile=/home/forge/app.com/worker.log

在本例中, numprocs指令让Supervisor运行8个 queue:work进程并监视它们,如果失败的话自动重启。配置文件创建好了之后,可以使用如下命令更新Supervisor配置并开启进程:

sudo supervisord -c /etc/supervisord.confsudo supervisorctl -c /etc/supervisor/supervisord.confsudo supervisorctl rereadsudo supervisorctl updatesudo supervisorctl start laravel-worker:*

要了解更多关于Supervisor的使用和配置,查看 Supervisor文档。此外,还可以使用Laravel Forge从web接口方便地自动配置和管理Supervisor配置。

4.2 后台队列监听器

Artisan命令 queue:work包含一个 --daemon选项来强制队列worker持续处理任务而不必重新启动框架。相较于 queue:listen命令该命令对CPU的使用有明显降低:

php artisan queue:work connection --daemonphp artisan queue:work connection --daemon --sleep=3php artisan queue:work connection --daemon --sleep=3 --tries=3

正如你所看到的, queue:work任务支持大多数 queue:listen中有效的选项。你可以使用 php artisan help queue:work任务来查看所有有效选项。

后台队列监听器编码考虑

后台队列worker在处理每个任务时不重启框架,因此,你要在任务完成之前释放资源,举个例子,如果你在使用GD库操作图片,那么就在完成时使用 imagedestroy释放内存。

类似的,数据库连接应该在后台长时间运行完成后断开,你可以使用 DB::reconnect方法确保获取了一个新的连接。

4.3 部署后台队列监听器

由于后台队列worker是常驻进程,不重启的话不会应用代码中的更改,所以,最简单的部署后台队列worker的方式是使用部署脚本重启所有worker,你可以通过在部署脚本中包含如下命令重启所有worker:

php artisan queue:restart

该命令会告诉所有队列worker在完成当前任务处理后重启以便没有任务被遗漏。

注意:这个命令依赖于缓存系统重启进度表,默认情况下,APC在CLI任务中无法正常工作,如果你在使用APC,需要在APC配置中添加 apc.enable_cli=1。

5、处理失败任务

由于事情并不总是按照计划发展,有时候你的队列任务会失败。别担心,它发生在我们大多数人身上!Laravel包含了一个方便的方式来指定任务最大尝试执行次数,任务执行次数达到最大限制后,会被插入到 failed_jobs表,失败任务的名字可以通过配置文件 config/queue.php来配置。

要创建一个 failed_jobs表的迁移,可以使用 queue:failed-table命令:

php artisan queue:failed-table

运行队列监听器的时候,可以在 queue:listen命令上使用 --tries开关来指定任务最大可尝试执行次数:

php artisan queue:listen connection-name --tries=3

5.1 失败任务事件

如果你想要注册一个队列任务失败时被调用的事件,可以使用 Queue::failing方法,该事件通过邮件或 HipChat通知团队。举个例子,我么可以在Laravel自带的 AppServiceProvider中附件一个回调到该事件:

<?phpnamespace App\Providers;use Queue;use Illuminate\Support\ServiceProvider;class AppServiceProvider extends ServiceProvider{    /**     * 启动应用服务     *     * @return void     */    public function boot()    {        Queue::failing(function ($connection, $job, $data) {            // Notify team of failing job...        });    }    /**     * 注册服务提供者     *     * @return void     */    public function register()    {        //    }}

任务类的失败方法

想要更加细粒度的控制,可以在队列任务类上直接定义 failed方法,从而允许你在失败发生时执行指定动作:

<?phpnamespace App\Jobs;use App\Jobs\Job;use Illuminate\Contracts\Mail\Mailer;use Illuminate\Queue\SerializesModels;use Illuminate\Queue\InteractsWithQueue;use Illuminate\Contracts\Bus\SelfHandling;use Illuminate\Contracts\Queue\ShouldQueue;class SendReminderEmail extends Job implements SelfHandling, ShouldQueue{    use InteractsWithQueue, SerializesModels;    /**     * 执行任务     *     * @param  Mailer  $mailer     * @return void     */    public function handle(Mailer $mailer)    {        //    }    /**     * 处理失败任务     *     * @return void     */    public function failed()    {        // Called when the job is failing...    }}

5.2 重试失败任务

要查看已插入到 failed_jobs数据表中的所有失败任务,可以使用Artisan命令 queue:failed:

php artisan queue:failed

该命令将会列出任务ID,连接,对列和失败时间,任务ID可用于重试失败任务,例如,要重试一个ID为5的失败任务,要用到下面的命令:

php artisan queue:retry 5

要重试所有失败任务,使用如下命令即可:

php artisan queue:retry all

如果你要删除一个失败任务,可以使用 queue:forget命令:

php artisan queue:forget 5

要删除所有失败任务,可以使用 queue:flush命令:

php artisan queue:flush
声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
您什么时候使用特质与PHP中的抽象类或接口?您什么时候使用特质与PHP中的抽象类或接口?Apr 10, 2025 am 09:39 AM

在PHP中,trait适用于需要方法复用但不适合使用继承的情况。1)trait允许在类中复用方法,避免多重继承复杂性。2)使用trait时需注意方法冲突,可通过insteadof和as关键字解决。3)应避免过度使用trait,保持其单一职责,以优化性能和提高代码可维护性。

什么是依赖性注入容器(DIC),为什么在PHP中使用一个?什么是依赖性注入容器(DIC),为什么在PHP中使用一个?Apr 10, 2025 am 09:38 AM

依赖注入容器(DIC)是一种管理和提供对象依赖关系的工具,用于PHP项目中。DIC的主要好处包括:1.解耦,使组件独立,代码易维护和测试;2.灵活性,易替换或修改依赖关系;3.可测试性,方便注入mock对象进行单元测试。

与常规PHP阵列相比,解释SPL SplfixedArray及其性能特征。与常规PHP阵列相比,解释SPL SplfixedArray及其性能特征。Apr 10, 2025 am 09:37 AM

SplFixedArray在PHP中是一种固定大小的数组,适用于需要高性能和低内存使用量的场景。1)它在创建时需指定大小,避免动态调整带来的开销。2)基于C语言数组,直接操作内存,访问速度快。3)适合大规模数据处理和内存敏感环境,但需谨慎使用,因其大小固定。

PHP如何安全地上载文件?PHP如何安全地上载文件?Apr 10, 2025 am 09:37 AM

PHP通过$\_FILES变量处理文件上传,确保安全性的方法包括:1.检查上传错误,2.验证文件类型和大小,3.防止文件覆盖,4.移动文件到永久存储位置。

什么是无效的合并操作员(??)和无效分配运算符(?? =)?什么是无效的合并操作员(??)和无效分配运算符(?? =)?Apr 10, 2025 am 09:33 AM

JavaScript中处理空值可以使用NullCoalescingOperator(??)和NullCoalescingAssignmentOperator(??=)。1.??返回第一个非null或非undefined的操作数。2.??=将变量赋值为右操作数的值,但前提是该变量为null或undefined。这些操作符简化了代码逻辑,提高了可读性和性能。

什么是内容安全策略(CSP)标头,为什么重要?什么是内容安全策略(CSP)标头,为什么重要?Apr 09, 2025 am 12:10 AM

CSP重要因为它能防范XSS攻击和限制资源加载,提升网站安全性。1.CSP是HTTP响应头的一部分,通过严格策略限制恶意行为。2.基本用法是只允许从同源加载资源。3.高级用法可设置更细粒度的策略,如允许特定域名加载脚本和样式。4.使用Content-Security-Policy-Report-Only头部可调试和优化CSP策略。

什么是HTTP请求方法(获取,发布,放置,删除等),何时应该使用?什么是HTTP请求方法(获取,发布,放置,删除等),何时应该使用?Apr 09, 2025 am 12:09 AM

HTTP请求方法包括GET、POST、PUT和DELETE,分别用于获取、提交、更新和删除资源。1.GET方法用于获取资源,适用于读取操作。2.POST方法用于提交数据,常用于创建新资源。3.PUT方法用于更新资源,适用于完整更新。4.DELETE方法用于删除资源,适用于删除操作。

什么是HTTP,为什么对Web应用程序至关重要?什么是HTTP,为什么对Web应用程序至关重要?Apr 09, 2025 am 12:08 AM

HTTPS是一种在HTTP基础上增加安全层的协议,主要通过加密数据保护用户隐私和数据安全。其工作原理包括TLS握手、证书验证和加密通信。实现HTTPS时需注意证书管理、性能影响和混合内容问题。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中