laravel 队列中处理 excel 上传

 余温
2020年12月03日 16时38分
 php

--laravel 队列 处理任务官方文档就基本很清晰了

跳转文档地址

看代码就比较清晰


<?php
namespace App\Jobs;
/**
 * 处理上传文件
 * Class Excel
 * @package App\Jobs
 */
class Excel implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public $tries = 2;  //队列错误重试次数

    public $timeout = 60 * 60 * 5;//队列执行超时时间(秒)




    /**
     *   初始化的时候设置参数为全局变量
     */
    public function __construct($fileUrl)
    {
        $this->fileUrl = $fileUrl;
    }


    /**
     * Execute the job.
     */
    public function handle()
    {
        //任务执行过程 导入excel
        \Excel::import(new ImportServiceExcel($this->fileUrl), $this->fileUrl);
    }
  /**
     * 任务失败处理
     * @param Exception $exception
     */
    public function failed(\Exception $exception)
    {
        self::unsuccessful($this->userInfo['id'],$exception);
    }
}

使用 horizon 管理队列

这个也是官方文档就很清晰了

horizon 文档地址

这个我使用的时候无法按照官方给的放假进行授权然后就是用了 www-authenticate认证 方法 添加一个中间件就 OK 这个也是比较简单的

namespace App\Http\Middleware;

use Closure;

class HorizonBasicAuth
{
    /**
     * 队列监控验证
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($request->getUser() != 'user' || $request->getPassword() != 'password') {
            $headers = array('WWW-Authenticate' => 'Basic');
            return response('Unauthorized', 401, $headers);
        }
        return $next($request);
    }
}

excel 导入

excel 导入是用的是 laravel-excel 照例还是先贴 文档地址 一般来说看文档能解决大部分问题 因为每次导入的 excel 数量还是比较大 一次导入的话很大的可能就是内存超出限制

使用队列导入 excel 主要原因还是 excel 数据量太大 导入需要时间太长 这样可以让用户不需要等待 也可以使用异步的方式

使用这个的分块导入还是比较好处理

<?php

namespace App\Imports;

use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\WithHeadingRow;//去除表头

//新增
use Maatwebsite\Excel\Concerns\WithChunkReading;

class ImportService implements ToCollection, WithChunkReading, WithHeadingRow
{

    private $batchSize = 500;
    private $task_id = 0;
    private $fileUrl = '';
    private $num = 0;
    private $data_array =[];

    /**
     * @param int $task_id
     * @param string $fileUrl
     */
    public function __construct(int $task_id,$fileUrl='')
    {
        $this->task_id = $task_id;
        $this->fileUrl = $fileUrl;
    }

    public function collection(Collection $rows)
    {

        $arr = array_chunk($rows->toArray(), $this->batchSize);
        foreach ($arr as $vo) {
            $this->createData($vo);
            $this->num += $this->batchSize;
         //$this->data_array 批量添加到数据库
             $this->data_array = [];
        }

    }



    // 每次读取多少条数据  可以根据自己的需求设置
    public function chunkSize(): int
    {
        return 5000;
    }
}

基本上这样就完美的搞定了这个功能

写在最后

第一个坑

一开是我是使用的 http 模仿的异步 大概就是这样

 <?php 
    $ch = curl_init(); 
    $curl_opt = array( 
      CURLOPT_URL, 'http://www.example.com/doRequest.php'
      CURLOPT_RETURNTRANSFER,1, 
      CURLOPT_TIMEOUT,1 
    ); 
    curl_setopt_array($ch, $curl_opt); 
    curl_exec($ch); 
    curl_close($ch); 
?>

这个方法使用中最严重的问题就是不稳定 有时候会导致不去执行

第二个坑

再就是 读 excel 的时候 我是每一行去数据库判断一个有没有重复值再去插入 这样就导致运行速度非常之慢 十万的数据就要执行几十分钟

目前的解决方案是 读取 excel 之后没五百条批量插入一次数据库 放弃判断重复值 在执行逻辑的时候判断是否重复 这样可以大大提升写入速度 大概四十几万数据读取写入只需要 三五分钟,效率几十倍的提升

这个期间我也使用过 xlswrite 读取速度相较于 laravel-excel 提升很多,但是问题就是安装的话没有 larvel-excel 好安装 毕竟是要安装 php 扩展。而且只支持 xlsx (别的格式可能是我没有发现使用方法)

最后最重要的一句 这个的最大瓶颈还是在数据库 读取excel 的速度其实影响并不是很大
上一篇: 限制访问次数
{{vo.nickname}}:{{vo.content}}

{{vo.time}} 回复


  • {{level.nickname}} 回复 {{level.father_nickname}}{{level.content}}
  • {{level.time}} 回复


@
登陆后评论