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

解决的问题:

● 耗时较长

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

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

● 请教下,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())]);        }    }    ....

达到的效果

c9646803419fe44d5e37122b9937f02.png

注意事项

QUEUE_DRIVER=sync 变更为 redis

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

队列排错参考:

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

最后

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

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

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

更多Laravel相关技术文章,请访问Laravel框架入门教程栏目进行学习!

以上就是后台执行超长时间任务解决方案的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/108397.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
在MySQL中,!的优先级如何?与 NOT 运算符相比的运算符取决于 HIGH_NOT_PRECEDENCE SQL 模式吗?
上一篇 2025年11月22日 20:57:34
在Sublime中使用Docker指令支持|整合容器开发环境技巧
下一篇 2025年11月22日 20:59:37

相关推荐

发表回复

登录后才能评论
关注微信