- _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日志,如我们预期一样生成了五条记录,非常完美。这样异步,队列的模型就已经搭建完毕了,下面我们来实现剩下的功能。