Laravel基于 Redis 实现任务队列的基本配置和使用

1、概述
在Web开发中,我们经常会遇到需要批量处理任务的场景,比如群发邮件、秒杀资格获取等,我们将这些耗时或者高并发的操作放到队列中异步执行可以有效缓解系统压力、提高系统响应速度和负载能力。

实现队列有多种方式,Laravel也支持多种队列实现驱动,比如数据库、Redis、Beanstalkd、IronMQ及Amazon SQS等,此外还支持同步方式实现队列(默认),甚至将队列驱动设置为null表示不使用队列。Laravel为这些队列驱动提供了统一的接口,从而方便我们任意切换驱动而不需要改变业务逻辑编码,提供代码复用性。

下面我们将以Redis驱动为例演示在Laravel如何实现队列创建、推送和执行。

2、配置文件
我们仍然从配置文件开始,首先我们需要在配置文件中配置默认队列驱动为Redis,队列配置文件是config/queue.php:

return [

    'default' => env('QUEUE_DRIVER', 'sync'),

    'connections' => [
        'sync' => [
            'driver' => 'sync',
        ],
        'database' => [
            'driver' => 'database',
            'table' => 'jobs',
            'queue' => 'default',
            'expire' => 60,
        ],
        'beanstalkd' => [
            'driver' => 'beanstalkd',
            'host' => 'localhost',
            'queue' => 'default',
            'ttr' => 60,
        ],
        'sqs' => [
            'driver' => 'sqs',
            'key' => 'your-public-key',
            'secret' => 'your-secret-key',
            'queue' => 'your-queue-url',
            'region' => 'us-east-1',
        ],
        'iron' => [
            'driver' => 'iron',
            'host' => 'mq-aws-us-east-1.iron.io',
            'token' => 'your-token',
            'project' => 'your-project-id',
            'queue' => 'your-queue-name',
            'encrypt' => true,
        ],
        'redis' => [
            'driver' => 'redis',
            'connection' => 'default',
            'queue' => 'default',
            'expire' => 60,
        ],
    ],

    'failed' => [
        'database' => 'mysql', 'table' => 'failed_jobs',
    ],
];
该配置文件第一个配置项default用于指定默认的队列驱动,这里我们将其值改为redis(实际上是修改.env中的QUEUE_DRIVER)。

connections配置项包含了Laravel支持的所有队列驱动,我们使用Redis驱动,所以需要配置redis项:connection对应config/database.php中redis的default配置;queue为默认队列名称;expire为队列任务过期时间(秒)。这里我们可以保持其默认配置不变。

failed配置项用于配置失败队列任务存放的数据库及数据表。这里我们需要按照自己的数据库配置对其做相应修改。

3、编写队列任务
本例中,我们将演示一个给用户发送新功能提醒邮件的例子。

首先我们通过如下Artisan命令创建任务类:

php artisan make:job SendReminderEmail --queued
--queued选项表示生成的任务类实现了ShouldQueue接口,会被推送到队列而不是同步执行。

运行成功后会在app/Jobs目录下生成一个SendReminderEmail.php,我们修改其内容如下:

<?php
namespace App\Jobs;

use App\Jobs\Job;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Bus\SelfHandling;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\User;
use Illuminate\Contracts\Mail\Mailer;
class SendReminderEmail extends Job implements SelfHandling, ShouldQueue
{

    use InteractsWithQueue, SerializesModels;
    protected $user;
   
    /**
     * Create a new job instance.
     *
     * @return void
     */

    public function __construct(User $user)
    {
        $this->user = $user;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle(Mailer $mailer)
    {
        $user = $this->user;
        $mailer->send('emails.reminder',['user'=>$user],function($message) use ($user){
            $message->to($user->email)->subject('新功能发布');
        });
    }
}
这里我们使用依赖注入引入了User和Mailer实例。User用于获取用户信息,Mailer用于发送邮件。这里的Mailer和前一节邮件发送中使用的Mail门面有异曲同工之效,它们最终调用的都是同一个类上的方法,这个类就是Illuminate\Mail\Mailer。

下面我们创建邮件局部视图resources/views/emails/reminder.blade.php:

亲爱的{{$user->name}},您好,Laravel学院新发布了XXX功能,立即去体验下吧:
<a href="http://laravelacademy.org">前往学院</a>
编写好任务类之后我们来看如何将任务推送到队列中:

4、推送队列任务
手动分发任务

我们可以使用控制器中的DispatchesJobs trait(该trait在控制器基类Controller.php中引入)提供的dispatch方法手动分发任务:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Mail;
use Storage;
use App\User;
use App\Jobs\SendReminderEmail;

class MailController extends Controller
{
    //其他方法

    //发送提醒邮件
    public function sendReminderEmail(Request $request,$id){
        $user = App\User::findOrFail($id);
        $this->dispatch(new SendReminderEmail($user));
    }
}
然后在routes.php中定义路由:

Route::get('mail/sendReminderEmail/{id}','MailController@sendReminderEmail');
运行队列监听器

在浏览器中访问http://laravel.app:8000/mail/sendReminderEmail/1,此时任务被推送到Redis队列中,我们还需要在命令行中运行Artisan命令执行队列中的任务。Laravel为此提供了三种Artisan命令:

queue:work 默认只执行一次队列请求, 当请求执行完成后就终止;
queue:listen 监听队列请求,只要运行着,就能一直接受请求,除非手动终止;
queue:work --daemon 同 listen 一样, 只要运行着,就能一直接受请求,不一样的地方是在这个运行模式下,当新的请求到来的时候,不重新加载整个框架,而是直接 fire 动作。能看出来, queue:work --daemon 是最高级的,一般推荐使用这个来处理队列监听。
注:使用 queue:work --daemon ,当更新代码的时候,需要停止,然后重新启动,这样才能把修改的代码应用上。
所以我们接下来在命令行中运行如下命令:

php artisan queue:work --daemon
然后去查看邮箱会收到提醒邮件:

Laravel中使用队列实现邮件发送

注:要保证任务执行成功,需要确保users表中id为1的记录email是一个有效邮箱。
当然你可以在控制器之外的其它地方使用dispatch分发任务,当然在此之前需要在该类中使用use DispatchesJobs。

推送任务到指定队列

上述操作将队列推送到默认队列,即配置文件中的default,当然你还可以将任务推送到指定队列:

public function sendReminderEmail(Request $request,$id){
    $user = App\User::findOrFail($id);
    $job = (new SendReminderEmail($user))->onQueue('emails');
    $this->dispatch($job);
}
延迟任务执行

除此之外,Laravel还支持延迟任务执行时间,这里我们指定延迟1分钟执行任务:

public function sendReminderEmail(Request $request,$id){
    $user = User::findOrFail($id);
    $job = (new SendReminderEmail($user))->delay(60);
    $this->dispatch($job);
}
从请求中分发任务

此外,我们还可以将HTTP请求实例映射到任务中,然后从请求实例中获取参数填充任务类的构造函数,如果请求中不包含该参数,甚至还可以传递额外参数,这可以通过DispatchesJobs trait提供的dispatchFrom方法来实现:

public function sendReminderEmail(Request $request,$id){
    $this->dispatchFrom('App\Jobs\SendReminderEmail',$request,['id'=>$id]);
}
当然我们需要对SendReminderEmail任务类的构造函数做如下修改:

public function __construct($id)
{
    $this->user = User::find($id);
}
构造函数中的$id就是从额外参数中获取到的。

时间: 2024-09-11 12:20:12

Laravel基于 Redis 实现任务队列的基本配置和使用的相关文章

基于redis的cas集群配置(转)

1.cas ticket统一存储 做cas集群首先需要将ticket拿出来,做统一存储,以便每个节点访问到的数据一致.官方提供基于memcached的方案,由于项目需要,需要做计入redis,根据官方例子改了一个基于redis版本的. public class RedisTicketRegistry extends AbstractDistributedTicketRegistry{ @NotNull private final RedisTemplate<String,Object> rei

基于Redis实现分布式锁以及任务队列_Redis

一.前言 双十一刚过不久,大家都知道在天猫.京东.苏宁等等电商网站上有很多秒杀活动,例如在某一个时刻抢购一个原价1999现在秒杀价只要999的手机时,会迎来一个用户请求的高峰期,可能会有几十万几百万的并发量,来抢这个手机,在高并发的情形下会对数据库服务器或者是文件服务器应用服务器造成巨大的压力,严重时说不定就宕机了,另一个问题是,秒杀的东西都是有量的,例如一款手机只有10台的量秒杀,那么,在高并发的情况下,成千上万条数据更新数据库(例如10台的量被人抢一台就会在数据集某些记录下 减1),那次这个

一个基于redis和disque实现的轻量级异步任务执行器

简介 horae是一个基于redis和disque实现的轻量级.高性能的异步任务执行器,它的核心是disque提供的任务队列,而队列有先进先出的时序关系,顾得名:horae. horae : 时序女神,希腊神话中司掌季节时间和人间秩序的三女神,又译"荷莱". horae的关注点不是队列服务的实现本身(已经有不少队列服务的实现了),而是希望借助于redis与disque提供的纯内存的高性能的队列机制,实现一个异步任务执行器.它可以自由配置任务来自哪种队列服务,它不关注任务执行的最终状态(

基于Redis的限流系统的设计

基于Redis的限流系统的设计,主要会谈及限流系统中限流策略这个功能的设计:在实现方面,算法使用的是令牌桶算法来,访问Redis使用lua脚本. 1.概念 限流是对系统的出入流量进行控制,防止大流量出入,导致资源不足,系统不稳定. 限流系统是对资源访问的控制组件,控制主要的两个功能:限流策略和熔断策略,对于熔断策略,不同的系统有不同的熔断策略诉求,有的系统希望直接拒绝.有的系统希望排队等待.有的系统希望服务降级.有的系统会定制自己的熔断策略,很难一一列举,所以本文只针对限流策略这个功能做详细的设

基于redis的分布式ID生成器

项目地址 https://github.com/hengyunabc/redis-id-generator 基于redis的分布式ID生成器. 准备 首先,要知道redis的EVAL,EVALSHA命令: http://redis.readthedocs.org/en/latest/script/eval.html http://redis.readthedocs.org/en/latest/script/evalsha.html 原理 利用redis的lua脚本执行功能,在每个节点上通过lua

Tomcat7基于Redis的Session共享

目前,为了使web能适应大规模的访问,需要实现应用的集群部署.集群最有效的方案就是负载均衡,而实现负载均衡用户没一个请求都有可能被分配到不固定的服务器上,这样我们首先要解决session的统一来保证无论用户的请求被转发到哪个服务器上都能保证用户的正常使用,即需要实现session的共享机制. 在集群系统下实现session统一的有如下几种方案: (1) 应用服务器间的session复制共享(如tomcat自带session共享) (2) 基于cache DB缓存的session共享 应用服务器间

基于Redis的分布式锁真的安全吗?(下)

自从我写完这个话题的上半部分之后,就感觉头脑中出现了许多细小的声音,久久挥之不去.它们就像是在为了一些鸡毛蒜皮的小事而相互争吵个不停.的确,有关分布式的话题就是这样,琐碎异常,而且每个人说的话听起来似乎都有道理.   今天,我们就继续探讨这个话题的后半部分.本文中,我们将从Antirez反驳Martin Kleppmann的观点开始讲起,然后会涉及到Hacker News上出现的一些讨论内容,接下来我们还会讨论到基于Zookeeper和Chubby的分布式锁是怎样的,并和Redlock进行一些对

laravel框架中环境与缓存使用配置

般一个项目的开发需要经历开发,测试,预发布,发布这四个流程. 因此在larave中对这个功能的支持也做的非常好来看代码.laravel默认使用的是production环境,也就是生产环境,那么我们怎么修改呢? 我们找到bootstrap文件夹下面的start.php文件的这几行代码:  代码如下 复制代码 $env = $app->detectEnvironment(array(     'local' => array('your-mechine-name'), )); 那么这个该怎么配置呢

分布式业务Redis安装与集群配置

       Redis在百度百科里的解释:Redis是一个开源的使用ANSI  C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API,包括C#.Java.PHP等等,甚至连Javascript都做了很好的封装.        可见Redis的数据是持久化的,可以分担一个项目中的部分业务,Redis的数据是存储在服务器内存当中的,这样可以极大的加快访问速度,因为内存的读取速度远远超过磁盘和数据库,这在很大程序的上解决了大并发的困惑:同时Redis和