Laravel Queue—消息队列任务
laravel队列的使用
队列可以通过多种方式实现,在config/queue.php配置connection
//这里配置了三种方式,具体选哪一种,需要在.env配置 QUEUE_CONNECTION=redis
'connections' => [
'sync' => [
'driver' => 'sync',
],
'database' => [
'driver' => 'database',
'table' => 'jobs',
'queue' => 'default',
'retry_after' => 90,
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => 90,
'block_for' => null,
],
],
这里以redis为例子。
1.安装Predis扩展包
$ composer require predis/predis
2.在.env配置redis连接配置
3.创建任务类,实现的时候就是把任务实例放入到队列中,消费的时候就是执行任务实例的handle方法
php artisan make:job SendEmail
会创建类文件app/jobs/SendEmail.php
其他重要属性:
public $tries = 5; //表示 任务最大尝试次数
public $timeout = 120; //单个任务运行超时时间
public function __construct(User $user)
{
$this->user = $user;
}
public function handle()
{
sleep(2);
echo '任务执行'.$this->user->name;
}
4.任务分发dispatch(就是写入队列)
delay就是延迟分发( 我们指定一个任务在分配后 10分钟内不可被处理 )
onQueue(‘sendEmail’),就在指定队列,如果没有指定,都会放到默认的队列中。
onConnection('redis2),就是指定redis服务连接。
public function add()
{
$user = new User();
$user->name = 'aabc';
$user->email = '[email protected]';
$user->password = '[email protected]';
$user->save();
//向job添加一个任务
\App\Jobs\SendEmail::dispatch($user)->delay(now()->addMinutes(1))- >onQueue('sendEmail');
echo '用户添加成功\n';
}
5.消费队列,会启动一个常驻进程来消费,我们也可以用命令来消费
php artisan queue:work //这个命令会执行所有的队列
php artisan queue:work redis2 //执行指定这个连接的队列
php artisan queue:work redis2 --queue=emails //执行指定队列
执行每个任务队列,系统都是常驻进程模式运行,所以在handle中要释放资源型变量。修改了代码后,也要注意重启消费进程
php artisan queue:restart
laravel队列实现原理
队列服务注册
protected function registerManager()
{
$this->app->singleton('queue', function ($app) {
return tap(new QueueManager($app), function ($manager) {
$this->registerConnectors($manager);
});
});
}
可以看出,队列的门面操作的是Illuminate\Queue\QueueManager类
重要属性protected $connections = [];protected $connectors = [];
$connectors
,该成员变量中存储着所有 laravel
支持的底层队列服务:'Database', 'Redis', 'Beanstalkd', 'Sqs'。 保存一个闭包,这个闭包就是返回 redisConnector
、SqsConnector
、DatabaseConnector
、BeanstalkdConnector
各种连接器,例如redisConnector
Illuminate\Queue\Connectors\RedisConnector
class QueueManager implements FactoryContract, MonitorContract
{
public function addConnector($driver, Closure $resolver)
{
$this->connectors[$driver] = $resolver;
}
}
$connections = []就是保存各种连接器执行connect方法返回的对象,比如
Illuminate\Queue\RedisQueue
protected function resolve($name) //这个方法就是返回Illuminate\Queue\RedisQueue
{
$config = $this->getConfig($name);
return $this->getConnector($config['driver'])
->connect($config)
->setConnectionName($name);
}
所以我们操作的很多方法其实都是使用Illuminate\Queue\RedisQueue类的方法,这就是实现队列的工具。
class RedisQueue extends Queue implements QueueContract
{
public function push($job, $data = '', $queue = null)
{
return $this->pushRaw($this->createPayload($job, $data), $queue);
}
public function pushOn($queue, $job, $data = '')
{
return $this->push($job, $data, $queue);
}
public function later($delay, $job, $data = '', $queue = null)
{
return $this->laterRaw($delay, $this->createPayload($job, $data), $queue);
}
public function laterOn($queue, $delay, $job, $data = '')
{
return $this->later($delay, $job, $data, $queue);
}
}