解决的问题:
● 耗时较长
● 各端无法调取相关任务进度进行反馈
● 自定义任务过后反馈结果
● 请教下,Laravel 如何让程序在后台执行超长时间的代码?
流程简述
● 使用异步队列执行相关任务
● 使用助手方法进行任务 / 进度创建
● 通过暴露接口反馈相关进度
助手类源码如下
<?php// +----------------------------------------------------------------------// | Do what we can do// +----------------------------------------------------------------------// | Date : 2019/9/11 - 9:25 AM// +----------------------------------------------------------------------// | Author: seebyyu :)// +----------------------------------------------------------------------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->sheet(); $detail = [ // 开始时间 'begin' => time(), // 标记号 'sheet' => $sheet, // 总长度 'total_len' => $len, // 当前长度 'schedule' => 0 ]; // 主体信息 $this->connect()->setex($this->prefix. ':'. $sheet, $this->seconds, serialize($detail)); // 初始化任务进度 $this->connect()->setex($this->prefix. ':schedule:'. $sheet, $this->seconds, 1); return $sheet; } /** * 设置任务内容 * * @param $sheet * @param $value * @return MissionFrom */ public function setTaskContent($sheet, $value) { if( $this->connect()->exists($this->prefix. ':'. $sheet)){ $this->connect()->setex($this->prefix. ':content:'. $sheet, $this->seconds, serialize($value)); } return $this; } /** * 获取任务内容 * * @param $sheet * @return MissionFrom */ public function getTaskContent($sheet) { return empty($data = $this->connect()->get($this->prefix. ':content:'. $sheet)) ? null : unserialize($data); } /** * 设置任务前缀 * * @param string $prefix * @return $this */ public function setPrefix($prefix = '') { $this->prefix = 'school:task:'. ($prefix ?: 'default'); return $this; } /** * 任务详情 * * @param string $sheet * @return array */ public function taskDetail($sheet = '') { $detail = $this->connect()->get($key = ($this->prefix. ':'. $sheet)); if( !empty($detail)){ $this->original = array_merge( unserialize($detail), [ 'schedule' => (int)$this->getSchedule($sheet), 'content' => $this->getTaskContent($sheet) ]); } return (array) $this->original; } /** * 进度递增 * * @param string $sheet * @return int */ public function increments($sheet = '') { $inc = 0; if( !empty($detail = $this->taskDetail($sheet)) && $detail['schedule'] connect()->incr($this->prefix. ':schedule:'. $sheet); } return $detail['schedule'] ?? $inc; } /** * 获取任务进度 * * @param string $sheet * @return string */ public function getSchedule($sheet = '') { return $this->connect()->exists($key = ($this->prefix. ':schedule:'. $sheet)) ? $this->connect()->get($key) : 0; } /** * 生成任务单号 */ private static function sheet() { return md5(Hash::make(date('YmdHis'))); } /** * 所有任务进度 * * @return array */ public function taskAll() { $task_group_list = []; // 分组 foreach( (array)$this->connect()->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->setPrefix($business)->taskDetail($key); } } return $task_group_list; } /** * @return IlluminateFoundationApplication|mixed */ public function connect() { return app('redis.connection'); }}
调用过程如下
sheet = $sheet; } /** * Execute the job. * * @return void */ public function handle() { // 自定义业务前缀 $prefix = 'export_students'; // 创建任务进度 $this->sheet = $this->setPrefix($prefix)->createTask($this->sheet, 20); // 开始执行任务 echo '任务开始:'. $this->sheet. "n"; for ($i = 1; $i setPrefix($prefix)->increments($this->sheet)). "n"; } // 追加结果 任何类型 $this->setPrefix($prefix)->setTaskContent($this->sheet, [ 'url' => 'http://www.baidu.com' ]); }}
控制器部分
.... /** * 学校pc端后台任务进度列表 * * @return array */ public function duties() { if( empty($key = request('key'))){ $key = md5(Hash::make(date('YmdHis'))); // 创建任务 $this->dispatch(new importExcel($key)); return $key; }else{ // 查询单条任务信息 // $this->setPrefix('export_students')->taskDetail($key); return success(['data' => array_merge([ // 导出每餐记录列表 'meal_records' => [], // 每日记录列表 'daily_records' => [], // 其他记录列表 'other_records' => [], // 照片库 'photo_gallery' => [], // 采购计划 'purchasing_plan' => [], // 凭证记录 'voucher_records' => [], // 食材库 'ingredient_records' => [], // 导入学生 'import_students' => [], // 导出学生 'export_students' => [] ], $this->taskAll())]); } } ....
达到的效果

注意事项
QUEUE_DRIVER=sync 变更为 redis
开发阶段强烈建议把 horizon 这玩意儿装上,Laravel 自带的报错异常我实在无力吐槽,不方便排错.
队列排错参考:
Laravel 队列:如何查看队列报错信息?
最后
● 代码上面的业务完全根据我自身项目编写,直接照搬 可能会引起不兼容。
● 分享 更多的是一种解决思路,希望能帮到后面的小伙伴。
● 如果对代码 有什么优化思路 或者 建议 也可以探讨下。
更多Laravel相关技术文章,请访问Laravel框架入门教程栏目进行学习!
以上就是后台执行超长时间任务解决方案的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/108397.html
微信扫一扫
支付宝扫一扫