- _nosay
laravel中队列的使用(一)
2017-08-15 15:28:08
试想一个场景,你需要从10000个URL中提取网页元素中的title标签。
你预期的结果只是把这10000个URL一股脑的放入提交框,然后点一下提交,期待程序很好的把这1000个title提取出来然后入库展现出来。
如果把这10000条数据,一条一条的遍历去执行的话,浏览器一直处于请求状态,不知道何时才能够执行好,这个等待的过程是让人崩溃的,足够让你的客户去怀疑人生,并拍案而起,大吼一声:什么垃圾玩意!
这个时候,异步+队列这个需求就出来了。我们来看一下使用laravel是如何优雅的解决相应的需求。
我们首先通过
php artisan make:controller StartController
命令生成一个开始任务的控制器,然后在路由中进行注册
Route::get('/getTitlesByUrl','StartController@index');相应StartController.php中初始代码为
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class StartController extends Controller
{
//
public function index()
{
echo "start job";
}
}我们通过url访问,得到start job的字符串,说明我们控制器已经注册完成,下面我们来开始,我们先模拟数据,创建一个数组,里面放上一些著名的网址当做测试。当然具体数据你可能从excel中获取,或者从txt中获取等,这些暂不再讨论内容。
$weburls = [ 'http://www.baidu.com/', 'http://www.taobao.com/', 'http://www.qq.com/', 'http://www.youku.com/', 'http://www.muzilong.cn/', ];
然后我们创建一个事件和一个监听器来完成相应的title标签提取,开始的时候,我们需要在app\Providders\EventServiceProvider.php中进行注册
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'App\Events\getTitlesByUrlEvent' => [
'App\Listeners\getTitlesByUrlListener',
],
];
/**
* Register any events for your application.
*
* @return void
*/
public function boot()
{
parent::boot();
//
}
}然后命令行执行
php artisan event:generate
生成相应文件,然后我们看到在app文件夹下,生成了Events 和 Listeners文件夹,在这两个文件夹下分别生成了getTitlesByUrlEvent.php 和 getTitlesByUrlListener.php文件
我们现在只需要把url一个个的传入event中即可,在laravel中,我们可以通过event()这个全局方法,如
event(new getTitlesByUrlEvent($value));
接下来我们StartController.php文件中内容变为
<?php
namespace App\Http\Controllers;
use App\Events\getTitlesByUrlEvent;
use Illuminate\Http\Request;
class StartController extends Controller
{
//
public function index()
{
$weburls = [
'http://www.baidu.com/',
'http://www.taobao.com/',
'http://www.qq.com/',
'http://www.youku.com/',
'http://www.muzilong.cn/',
];
foreach($weburls as $key => $value)
{
event(new getTitlesByUrlEvent($value));
}
}
}getTitlesByUrlEvent.php文件内容为
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class getTitlesByUrlEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $url;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($url)
{
//
$this->url = $url;
}
/**
* Get the channels the event should broadcast on.
*
* @return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}getTitlesByUrlListener.php内容为:
<?php
namespace App\Listeners;
use App\Events\getTitlesByUrlEvent;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Log;
class getTitlesByUrlListener implements ShouldQueue
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param getTitlesByUrlEvent $event
* @return void
*/
public function handle(getTitlesByUrlEvent $event)
{
//
$url = $event->url;
Log::info("Now Let's get the title by ".$url);
}
}其中采集url title标签功能暂未完善,先测试一下。注意,我们在监听器中实现了 ShouldQueue 接口,也就是说用到了队列,所以我们需要修改一下相应的配置文件,以及生成相应的任务表,修改.env文件,让QUEUE_DRIVER的值为database,然后在控制台执行
php artisan queue:table php artisan queue:failed-table php artisan migrate
生成相应的表文件,大功告成,这时我们执行一下,并且在控制台执行
php artisan queue:work --daemon
然后查看LOG日志,如我们预期一样生成了五条记录,非常完美。这样异步,队列的模型就已经搭建完毕了,下面我们来实现剩下的功能。