Mysql Laravel文件上载超时-是否向updateOrCreate添加块?

Mysql Laravel文件上载超时-是否向updateOrCreate添加块?,mysql,laravel,laravel-5,laravel-excel,Mysql,Laravel,Laravel 5,Laravel Excel,我试图上传一个用户csv文件并将数据传递到数据库中,但由于csv/行的大小,它一直超时。必须检查数据是否已经在数据库中,并进行更新或创建 我已经在CSV上应用了一个块来读取数据,但不知道是否可以在上传到数据库部分添加一个块 这是我的功能 public function import(Request $request) { if($request->file('imported-file')) { $path = $request->file('import

我试图上传一个用户csv文件并将数据传递到数据库中,但由于csv/行的大小,它一直超时。必须检查数据是否已经在数据库中,并进行更新或创建

我已经在CSV上应用了一个块来读取数据,但不知道是否可以在上传到数据库部分添加一个块

这是我的功能

public function import(Request $request) {

    if($request->file('imported-file')) {

        $path = $request->file('imported-file')->getRealPath();

        $data = Excel::filter('chunk')->load($path)->chunk(200, function($results) {

            foreach($results as $row) {

                if(!empty($row['postcode'])) {

                    $url = "https://maps.googleapis.com/maps/api/geocode/xml?address=".urlencode($row['postcode'])."&region=uk&key=";
                    $tmp = file_get_contents($url);
                    $xml = simplexml_load_string($tmp);

                    if((string)$xml->status == 'OK' && isset($xml->result[0])) {

                        $lat = 0;
                        $lng = 0;

                        if(isset($xml->result[0]->geometry->location->lat)) {
                            $lat = (string)$xml->result[0]->geometry->location->lat;
                        }
                        if(isset($xml->result[0]->geometry->location->lng)) {
                            $lng = (string)$xml->result[0]->geometry->location->lng;
                        }

                    }

                    Import::updateOrCreate(
                        [
                            'sitecode' => $row['sitecode']
                        ],
                        [
                            'sitecode' => $row['sitecode'],
                            'sitename' => $row['sitename'],
                            'address_1' => $row['address_1'],
                            'address_2' => $row['address_2'],
                            'address_town' => $row['address_town'],
                            'address_postcode' => $row['postcode'],
                            'charity' => $row['charity'],
                            'latitude' => $lat,
                            'longitude' => $lng,
                            'approved' => 1
                        ]
                    );

                } else {

                    // Postcode not valid!!!

                }


            } // endforeach

            Session::flash('sucess', 'Import was sucessful.');
            return redirect()->route('locations');

        });

    } else {

        Session::flash('error', 'Please select a file to upload!');
        return back();

    }

}

您的问题与服务器的配置有关,您必须了解,在实时执行长时间运行的任务时,许多事情可能会出错

如果您使用的是Nginx/PHP-FPM设置,那么必须查看Nginx、PHP和PHP-FPM配置文件

PHP配置 让我们从PHP开始。打开
/etc/php//fpm/php.ini
文件并搜索
最大执行时间
。你应该找到类似的东西

max_execution_time = 30
这意味着每个请求的持续时间不能超过30秒。如果您需要更多时间,请增加此数字,例如

max_execution_time = 300
request_terminate_timeout = 400
5分钟

然后让我们检查一下PHP-FPM配置。打开池配置,如
/etc/php//fpm/pool.d/www.conf
,搜索
请求\终止\超时时间
。在我的配置中,我禁用了它:

; Default Value: 0
;request_terminate_timeout = 0
默认值为0(已禁用),但如果已启用该值,则应增加该值,例如

max_execution_time = 300
request_terminate_timeout = 400
在PHP-FPM杀死一个子进程之前400秒。如果您给出一个数字,请使用高于
max\u execution\u time
的值,否则您的进程将被PHP-FPM终止,忽略最大执行时间

Nginx配置 最后,查看
/etc/Nginx/sites available/yoursite.conf
中的Nginx配置。在这里,您应该可以找到一个配置Nginx和PHP-FPM之间通信的部分。您可以在这里找到
fastcgi\u read\u timeout
,这是Nginx等待PHP-FPM返回某些数据的最长时间:

location ~ \.php$ {
    # ...
    fastcgi_read_timeout 300;
    # ...
}
如果300秒后PHP-FPM没有返回任何内容,Nginx将终止连接。在您的情况下,在长时间运行的进程之后将数据发送回Web服务器,因此所需时间不会超过300秒。您应该将该数字更改为与您在PHP配置中输入的数字兼容的数字

总结 如果您认为您的处理可能需要30分钟,请使用以下数字:

  • /etc/php//fpm/php.ini
    中:

    max_execution_time = 1800        ; 1800 secs = 30 minutes
    
  • /etc/php//fpm/pool.d/www.conf
    中:

    request_terminate_timeout = 0    ; no timeout, or greater than 1800
    
    fastcgi_read_timeout = 2000;     # 2000 secs, or at least greater than the previous twos
    
  • /etc/nginx/sites available/yoursite.conf
    中:

    request_terminate_timeout = 0    ; no timeout, or greater than 1800
    
    fastcgi_read_timeout = 2000;     # 2000 secs, or at least greater than the previous twos
    
通过这种组合,
max_execution_time
将在其他组合中起支配作用,您将知道您的进程有30分钟的运行时间,因为PHP-FPM和Nginx超时应该发生在PHP超时之后

不要忘记客户端 如果您使用的是AJAX上传库,请检查它的配置,因为它可能会对完整的AJAX上传请求施加另一个超时

例如,默认情况下使用30秒超时。您的服务器可能会运行很长时间,但在短时间之后,您的javascript库将终止连接

通常可以更改该值。使用dropzone,您可以使用设置2100秒的超时

var myDropzone = new Dropzone("#uploader", {
    // ...
    timeout: "2100",
    // ...
});
同样,使用比Nginx上的值更高的值

长时间运行的任务:正确的方法 然而,您的方法又快又脏,即使我确信它适合您的情况,最好还是走另一条路:

  • 不要在上传后立即进行CSV处理
  • 相反,上传文件,将其放入队列中,并通知客户端稍后再检查
  • 使用队列工作者在后台执行CSV处理
  • 请查看队列()上的Laravel文档

    通过这种方法,您的用户将获得即时反馈,您将不再有超时问题!(从理论上讲,队列中的后台工作也可以按时间安排,但这是另一回事。)


    我希望这能有所帮助:)

    设置时间限制可能会对@RaymondNijland有所帮助,但仍然没有什么影响。嗨,谢谢你抽出时间写一封冗长的回复。我接受了你的建议,增加了一个工作/队列。我上传CSV,然后分派一个作业并处理CSV,然后从那里上传到数据库。我运行php artisan队列:工作正常!在我的macbook上就是这样。我已经将repo下载到我的imac上,完全相同,但是当我运行work命令时,我只是像一个无限循环一样一遍又一遍地得到它?[2017-11-29 11:48:21]处理:App\Jobs\ProcessCSV[2017-11-29 11:48:22]处理:App\Jobs\ProcessCSV有什么想法吗?可能你正面临工作到期和重审()。队列配置(
    config/queue.php
    )中有一个默认值为90秒的
    retry\u after
    选项。之后,如果作业没有完成,工人将重新开始。还要确保有一个足够大的worker
    --timeout
    (或者忽略这些选项,我认为默认值是no timeout)。