后台执行超长时间任务解决方案

解决的问题:

● 耗时较长

● 各端无法调取相关任务进度进行反馈

● 自定义任务过后反馈结果

● 请教下,laravel 如何让程序在后台执行超长时间的代码?

流程简述

● 使用异步队列执行相关任务

● 使用助手方法进行任务 / 进度创建

● 通过暴露接口反馈相关进度

助手类源码如下

<?php // +---------------------------------------------------------------------- // | Do what we can do // +---------------------------------------------------------------------- // | Date  : 2019/9/11 - 9:25 AM // +---------------------------------------------------------------------- // | Author: seebyyu <seebyyu@gmail.com> :) // +---------------------------------------------------------------------- namespace AppLibSupport; trait MissionFrom {     /**      * 标记前缀 模块名称#业务模块#板块标记      *      * @var string      */     public $prefix = 'school:task:default';     /**      * 任务详情      * @var array      */     public $original = [];     /**      * redis 链接      *      * The Redis factory implementation.      *      * @var IlluminateRedisConnectionsConnection      */     protected $redis;     /**      * 任务存在有效期      *      * @var int      */     protected $seconds = 600;     /**      * 创建任务      *      * @param string $sheet      * @param int $len 总长度      * @return string      */     public function createTask($sheet = '', $len = 100)     {         $sheet = $sheet ?: $this-&gt;sheet();         $detail = [             //  开始时间             'begin' =&gt; time(),             //  标记号             'sheet' =&gt; $sheet,             //  总长度             'total_len' =&gt; $len,             //  当前长度             'schedule' =&gt; 0         ];         //  主体信息         $this-&gt;connect()-&gt;setex($this-&gt;prefix. ':'. $sheet, $this-&gt;seconds, serialize($detail));         //  初始化任务进度         $this-&gt;connect()-&gt;setex($this-&gt;prefix. ':schedule:'. $sheet, $this-&gt;seconds, 1);         return $sheet;     }     /**      * 设置任务内容      *      * @param $sheet      * @param $value      * @return MissionFrom      */     public function setTaskContent($sheet, $value)     {         if( $this-&gt;connect()-&gt;exists($this-&gt;prefix. ':'. $sheet)){             $this-&gt;connect()-&gt;setex($this-&gt;prefix. ':content:'. $sheet, $this-&gt;seconds, serialize($value));         }         return $this;     }     /**      * 获取任务内容      *      * @param $sheet      * @return MissionFrom      */     public function getTaskContent($sheet)     {         return empty($data = $this-&gt;connect()-&gt;get($this-&gt;prefix. ':content:'. $sheet)) ? null : unserialize($data);     }     /**      * 设置任务前缀      *      * @param string $prefix      * @return $this      */     public function setPrefix($prefix = '')     {         $this-&gt;prefix = 'school:task:'. ($prefix ?: 'default');         return $this;     }     /**      * 任务详情      *      * @param string $sheet      * @return array      */     public function taskDetail($sheet = '')     {         $detail = $this-&gt;connect()-&gt;get($key = ($this-&gt;prefix. ':'. $sheet));         if( !empty($detail)){             $this-&gt;original = array_merge( unserialize($detail), [                 'schedule' =&gt; (int)$this-&gt;getSchedule($sheet),                 'content' =&gt; $this-&gt;getTaskContent($sheet)             ]);         }         return (array) $this-&gt;original;     }     /**      * 进度递增      *      * @param string $sheet      * @return int      */     public function increments($sheet = '')     {         $inc = 0;         if( !empty($detail = $this-&gt;taskDetail($sheet)) &amp;&amp;             $detail['schedule'] connect()-&gt;incr($this-&gt;prefix. ':schedule:'. $sheet);         }         return $detail['schedule'] ?? $inc;     }     /**      * 获取任务进度      *      * @param string $sheet      * @return string      */     public function getSchedule($sheet = '')     {         return $this-&gt;connect()-&gt;exists($key = ($this-&gt;prefix. ':schedule:'. $sheet)) ? $this-&gt;connect()-&gt;get($key) : 0;     }     /**      * 生成任务单号      */     private static function sheet()     {         return md5(Hash::make(date('YmdHis')));     }     /**      * 所有任务进度      *      * @return array      */     public function taskAll()     {         $task_group_list = [];         //  分组         foreach( (array)$this-&gt;connect()-&gt;keys('school:task:*') as $task) {             if( count($task_item = explode(':', $task)) == 4){                 list($model, $model_name, $business, $key) = $task_item;                 $task_group_list[$business][] = $this-&gt;setPrefix($business)-&gt;taskDetail($key);             }         }         return $task_group_list;     }     /**      * @return IlluminateFoundationApplication|mixed      */     public function connect()     {         return app('redis.connection');     } }

调用过程如下

<?php namespace AppJobs; use AppLibSupportMissionFrom; use IlluminateBusQueueable; use IlluminateQueueSerializesModels; use IlluminateQueueInteractsWithQueue; use IlluminateContractsQueueShouldQueue; use IlluminateFoundationBusDispatchable; /**  * Excel 导入  *  * Class importExcel  * @package AppJobs  */ class importExcel implements ShouldQueue {     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, MissionFrom;     /**      * 任务运行的超时时间。      *      * @var int      */     public $timeout = 300;     /**      * @var string      */     public $sheet;     /**      * importExcel constructor.      * @param $sheet      */     public function __construct($sheet = &#39;&#39;)     {         $this->sheet = $sheet;     }     /**      * Execute the job.      *      * @return void      */     public function handle()     {         //  自定义业务前缀         $prefix = 'export_students';         //  创建任务进度         $this-&gt;sheet = $this-&gt;setPrefix($prefix)-&gt;createTask($this-&gt;sheet, 20);         //  开始执行任务         echo '任务开始:'. $this-&gt;sheet. "n";         for ($i = 1; $i setPrefix($prefix)-&gt;increments($this-&gt;sheet)). "n";         }         //  追加结果 任何类型         $this-&gt;setPrefix($prefix)-&gt;setTaskContent($this-&gt;sheet, [             'url' =&gt; 'http://www.baidu.com'         ]);     } }

控制器部分

....     /**      * 学校pc端后台任务进度列表      *      * @return array      */     public function duties()     {         if( empty($key = request('key'))){             $key = md5(Hash::make(date('YmdHis')));             //  创建任务             $this-&gt;dispatch(new importExcel($key));             return $key;         }else{             //  查询单条任务信息             //  $this-&gt;setPrefix('export_students')-&gt;taskDetail($key);             return success(['data' =&gt; array_merge([                 //  导出每餐记录列表                 'meal_records' =&gt; [],                 //  每日记录列表                 'daily_records' =&gt; [],                 //  其他记录列表                 'other_records' =&gt; [],                 //  照片库                 'photo_gallery' =&gt; [],                 //  采购计划                 'purchasing_plan' =&gt; [],                 //  凭证记录                 'voucher_records' =&gt; [],                 //  食材库                 'ingredient_records' =&gt; [],                 //  导入学生                 'import_students' =&gt; [],                 //  导出学生                 'export_students' =&gt; []             ], $this-&gt;taskAll())]);         }     }     ....

达到的效果

后台执行超长时间任务解决方案

注意事项

QUEUE_DRIVER=sync 变更为 redis

开发阶段强烈建议把 horizon 这玩意儿装上,Laravel 自带的报错异常我实在无力吐槽,不方便排错.

队列排错参考:

Laravel 队列:如何查看队列报错信息?

最后

● 代码上面的业务完全根据我自身项目编写,直接照搬 可能会引起不兼容。

● 分享 更多的是一种解决思路,希望能帮到后面的小伙伴。

● 如果对代码 有什么优化思路 或者 建议 也可以探讨下。

更多Laravel相关技术文章,请访问Laravel 队列:如何查看队列报错信息?栏目进行学习!

© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享