上一篇讲了Lumen配置Redis,现在来讲一下,如何实现消息队列

2、编写任务类

2.1  任务类结构

默认情况下,应用的所有队列任务都存放在app/Jobs目录。任务类非常简单,正常情况下只包含一个当队列处理该任务时被执行的handle方法,让我们看一个任务类的例子:、

<?php

namespace App\Jobs;

use App\User;
use App\Jobs\Job;
//use Illuminate\Contracts\Mail\Mailer;//略过邮箱操作
use Illuminate\Queue\SerializesModels;
//use Illuminate\Queue\InteractsWithQueue;//会引起jobs的冲突
//use Illuminate\Contracts\Bus\SelfHandling;//已自动实现
use Illuminate\Contracts\Queue\ShouldQueue; //class SendReminderEmail extends Job implements SelfHandling, ShouldQueue
class SendReminderEmail extends Job implements ShouldQueue
{
//use InteractsWithQueue, SerializesModels;
use 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)
{
sleep(5);
//TODO 这里可以往数据库表插入一条记录,可以看出异步效果
}
}

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

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

出错

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

手动释放任务

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

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

检查尝试运行次数

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

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

  

3、推送任务到队列

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

?php

namespace 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));
}
}

为任务指定队列

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

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

<?php

namespace 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\Queueable trait提供:

<?php

namespace 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 从请求中分发任务

映射HTTP请求变量到任务中很常见,Lumen提供了一些帮助函数让这种实现变得简单,而不用每次请求时手动执行映射。让我么看一下 DispatchesJobs trait上的dispatchFrom方法。默认情况下,该trait包含在Lumen控制器基类中:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller; class CommerceController extends Controller{
/**
* 处理指定订单
*
* @param Request $request
* @param int $id
* @return Response
*/
public function processOrder(Request $request, $id)
{
// 处理请求...
$this->dispatchFrom('App\Jobs\ProcessOrder', $request);
}
}

  

该方法检查给定任务类的构造函数并从HTTP请求(或者其它ArrayAccess对象)中解析变量来填充任务需要的构造函数参数。所以,如果我们的任务类在构造函数中接收一个productId变量,该任务将会尝试从HTTP请求中获取productId参数。

你还可以传递一个数组作为dispatchFrom方法的第三个参数。该数组用于填充所有请求中不存在的构造函数参数:

$this->dispatchFrom('App\Jobs\ProcessOrder', $request, [
'taxPercentage' => 20,
]);

  

4、运行队列监听器

开启任务监听器

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

php artisan queue:listen

  

每次执行控制器对应方法,执行任务写入,然后再异步执行对应任务,后面两次前后都相隔了5秒,因为加了sleep(5),不过执行sleep前就返回了结果!

下一篇再详细分析具体的操作方法和处理方法

Lumen开发:结合Redis实现消息队列(2)的更多相关文章

  1. Lumen开发:结合Redis实现消息队列(1)

    1.简介 Lumen队列服务为各种不同的后台队列提供了统一的API.队列允许你推迟耗时任务(例如发送邮件)的执行,从而大幅提高web请求速度. 1.1 配置 .env文件的QUEUE_DRIVER选项 ...

  2. Redis 做消息队列

    一般来说,消息队列有两种场景,一种是发布者订阅者模式,一种是生产者消费者模式.利用redis这两种场景的消息队列都能够实现.定义: 生产者消费者模式:生产者生产消息放到队列里,多个消费者同时监听队列, ...

  3. Redis作为消息队列服务场景应用案例

    NoSQL初探之人人都爱Redis:(3)使用Redis作为消息队列服务场景应用案例   一.消息队列场景简介 “消息”是在两台计算机间传送的数据单位.消息可以非常简单,例如只包含文本字符串:也可以更 ...

  4. redis resque消息队列

    Resque 目前正在学习使用resque .resque-scheduler来发布异步任务和定时任务,为了方便以后查阅,所以记录一下. resque和resque-scheduler其优点在于功能比 ...

  5. 【springboot】【redis】springboot+redis实现发布订阅功能,实现redis的消息队列的功能

    springboot+redis实现发布订阅功能,实现redis的消息队列的功能 参考:https://www.cnblogs.com/cx987514451/p/9529611.html 思考一个问 ...

  6. 【Redis】php+redis实现消息队列

    在项目中使用消息队列一般是有如下几个原因: 把瞬间服务器的请求处理换成异步处理,缓解服务器的压力 实现数据顺序排列获取 redis实现消息队列步骤如下: 1).redis函数rpush,lpop 2) ...

  7. Redis除了做缓存--Redis做消息队列/Redis做分布式锁/Redis做接口限流

    1.用Redis实现消息队列 用命令lpush入队,rpop出队 Long size = jedis.lpush("QueueName", message);//返回存放的数据条数 ...

  8. sping+redis实现消息队列的乱码问题

    使用spring支持redis实现消息队列,参考官方样例:https://spring.io/guides/gs/messaging-redis/ 实现后在运行过程中发现消费者在接收消息时会出现乱码的 ...

  9. 程序员过关斩将--redis做消息队列,香吗?

    Redis消息队列 在程序员这个圈子打拼了太多年,见过太多的程序员使用redis,其中一部分喜欢把redis做缓存(cache)使用,其中最典型的当属存储用户session,除此之外,把redis作为 ...

  10. Lumen开发:结合Redis实现消息队列(3)

    4.运行队列监听器 开启任务监听器 Lumen包含了一个Artisan命令用来运行推送到队列的新任务.你可以使用queue:listen命令运行监听器: php artisan queue:liste ...

随机推荐

  1. [置顶] kubernetes资源对象--ConfigMap

    原理 很多生产环境中的应用程序配置较为复杂,可能需要多个config文件.命令行参数和环境变量的组合.使用容器部署时,把配置应该从应用程序镜像中解耦出来,以保证镜像的可移植性.尽管Secret允许类似 ...

  2. wp8开发时模拟器无法联网解决方法

    关于模拟器无法联网的正常解决方案在网上有很多 这里讲的是我在做测试的时候模拟器无法上网的特殊情况 由于使用的是无线网络 可能有一些差别 过程如图: 启动模拟器 如果之前没有设置过模拟器的交换器则会出现 ...

  3. smarty在循环的时候计数来显示这是第几次循环的功能

    想必有很多人比较喜欢这个smarty循环的时候有个变量增加的功能或比较需要这个功能吧?其实不需要额外的变量,当然你也许根本用不了.我们用smarty内置的就可以了.就是smarty有foreach和s ...

  4. Effective C++--经验条款

    高效C++ --模板与泛型编程 在C++中模板体现的是编译期多态,virtual体现的是执行期多态. 关于typename的双重含义: 在声明template參数时,不论使用keywordclass或 ...

  5. mysql热备及查询mysql操作日志

    mysql热备 1 查看mysql版本,保证主库低于等于从库 2 主库配置:   A 需要打开支持日志功能:log-bin=mysql-bin   B 提供server-id:server-id=1  ...

  6. 【Excle数据透视表】如何调整压缩形式显示下的缩进字符数

    调整前:                                                                                                 ...

  7. 命令行添加pod示例

    1.创建AlamFireDemo 工程,关闭工程 2.进入到工程目录 执行 pod init 命令 生成 PodFile文件 3.vi PodFile编辑该文件 启用:platform :ios, ' ...

  8. ajax个人学习笔记

    1. function createXHR(){ if(typeof XMLHttpRequest != 'undefined'){ return new XMLHttpRequest(); }els ...

  9. Android下ListView的分页(9.6)

    1 http://www.cnblogs.com/noTice520/archive/2012/02/10/2345057.html 2 http://www.92coding.com/blog/in ...

  10. 高抛低吸T+0操作要领(目前行情短线炒作的必备技能)

    最近的行情只能用操蛋来形容,但是危机中不乏机会.现在已经不是之前行情的思路,那着一个股票长线抱着,即使是好的牛股,也经不起目前行情的这 么折腾.所以,现在最适合的操作方式就是高抛低吸.今天低吸保不准明 ...