Laravel 文件上传超时 - 向 updateOrCreate 添加块?
Laravel file upload timing out - adding chunk to updateOrCreate?
我正在尝试上传用户 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'])."®ion=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();
}
}
您的问题与您的服务器配置有关,您必须明白,当您实时执行长时间 运行ning 任务时,很多事情都可能出错。
如果您使用的是 Nginx/PHP-FPM 设置,则必须查看 Nginx、PHP 和 PHP-FPM 配置文件。
PHP配置
让我们从PHP开始。打开 /etc/php/<phpversion>/fpm/php.ini
文件并搜索 max_execution_time
。你应该找到像
这样的东西
max_execution_time = 30
表示每次请求的时长不超过30秒。如果您需要更多时间,请增加此数字,例如
max_execution_time = 300
5 分钟。
然后让我们检查一下PHP-FPM 配置。打开您的池配置,例如 /etc/php/<phpversion>/fpm/pool.d/www.conf
并搜索 request_terminate_timeout
。在我的配置中,我将其禁用:
; Default Value: 0
;request_terminate_timeout = 0
默认值为 0(禁用),但如果您启用了它,则应增加数字,例如
request_terminate_timeout = 400
400 秒,然后 PHP-FPM 终止一个子进程。如果您给出一个数字,请使用高于 max_execution_time
的数字,否则您的进程将被 PHP-FPM 杀死,而忽略最大执行时间。
Nginx 配置
最后看看/etc/nginx/sites-available/yoursite.conf
中的Nginx配置。在那里你应该找到配置 Nginx 和 PHP-FPM 之间的通信的部分。在那里你找到 fastcgi_read_timeout
,这是 Nginx 等待 PHP-FPM 到 return 一些数据的最长时间:
location ~ \.php$ {
# ...
fastcgi_read_timeout 300;
# ...
}
如果 300 秒后 PHP-FPM 没有 returned 任何东西,Nginx 将终止连接。在您的情况下,您在 long-运行ning 过程后将数据发送回网络服务器,因此不会超过 300 秒。您应该将此数字更改为与您在 PHP 配置中输入的数字兼容的数字。
总结
如果您认为处理最多需要 30 分钟,请使用如下数字:
在/etc/php/<phpversion>/fpm/php.ini
:
max_execution_time = 1800 ; 1800 secs = 30 minutes
在/etc/php/<phpversion>/fpm/pool.d/www.conf
:
request_terminate_timeout = 0 ; no timeout, or greater than 1800
在/etc/nginx/sites-available/yoursite.conf
:
fastcgi_read_timeout = 2000; # 2000 secs, or at least greater than the previous twos
有了这个组合,max_execution_time
将统治其他进程,你会知道你的进程有 30 分钟的 运行ning 时间,因为 PHP-FPM 和 Nginx 超时应该在 PHP 之后发生。
不要忘记客户端
如果您使用的是 AJAX 上传库,请同时检查其配置,因为它可能会对完整的 AJAX 上传请求施加另一个超时。
例如,dropzonejs 默认使用 30 秒超时。您的服务器可能会 运行 很长时间,但在这么短的时间之后,您的 javascript 库将终止连接。
通常您可以更改该值。使用 dropzone,您可以使用
设置 2100 秒的超时
var myDropzone = new Dropzone("#uploader", {
// ...
timeout: "2100",
// ...
});
同样,使用比 Nginx 更高的值。
长运行宁任务:正确的方法
但是,你的方法又快又脏,即使我确定它适合你的情况,最好还是走另一条路:
- 不要在上传后立即进行 CSV 处理
- 相反,上传文件,将其放入队列中并通知客户稍后再回来查看
- 使用队列工作者在后台进行 CSV 处理
请查看有关队列的 Laravel 文档 (https://laravel.com/docs/5.5/queues)。
通过这种方法,您的用户将立即得到反馈,您将不会再遇到超时问题! (好吧,理论上:来自队列的后台作业也可以超时,但那是另一回事了。)
希望对您有所帮助:)
我正在尝试上传用户 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'])."®ion=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();
}
}
您的问题与您的服务器配置有关,您必须明白,当您实时执行长时间 运行ning 任务时,很多事情都可能出错。
如果您使用的是 Nginx/PHP-FPM 设置,则必须查看 Nginx、PHP 和 PHP-FPM 配置文件。
PHP配置
让我们从PHP开始。打开 /etc/php/<phpversion>/fpm/php.ini
文件并搜索 max_execution_time
。你应该找到像
max_execution_time = 30
表示每次请求的时长不超过30秒。如果您需要更多时间,请增加此数字,例如
max_execution_time = 300
5 分钟。
然后让我们检查一下PHP-FPM 配置。打开您的池配置,例如 /etc/php/<phpversion>/fpm/pool.d/www.conf
并搜索 request_terminate_timeout
。在我的配置中,我将其禁用:
; Default Value: 0
;request_terminate_timeout = 0
默认值为 0(禁用),但如果您启用了它,则应增加数字,例如
request_terminate_timeout = 400
400 秒,然后 PHP-FPM 终止一个子进程。如果您给出一个数字,请使用高于 max_execution_time
的数字,否则您的进程将被 PHP-FPM 杀死,而忽略最大执行时间。
Nginx 配置
最后看看/etc/nginx/sites-available/yoursite.conf
中的Nginx配置。在那里你应该找到配置 Nginx 和 PHP-FPM 之间的通信的部分。在那里你找到 fastcgi_read_timeout
,这是 Nginx 等待 PHP-FPM 到 return 一些数据的最长时间:
location ~ \.php$ {
# ...
fastcgi_read_timeout 300;
# ...
}
如果 300 秒后 PHP-FPM 没有 returned 任何东西,Nginx 将终止连接。在您的情况下,您在 long-运行ning 过程后将数据发送回网络服务器,因此不会超过 300 秒。您应该将此数字更改为与您在 PHP 配置中输入的数字兼容的数字。
总结
如果您认为处理最多需要 30 分钟,请使用如下数字:
在
/etc/php/<phpversion>/fpm/php.ini
:max_execution_time = 1800 ; 1800 secs = 30 minutes
在
/etc/php/<phpversion>/fpm/pool.d/www.conf
:request_terminate_timeout = 0 ; no timeout, or greater than 1800
在
/etc/nginx/sites-available/yoursite.conf
:fastcgi_read_timeout = 2000; # 2000 secs, or at least greater than the previous twos
有了这个组合,max_execution_time
将统治其他进程,你会知道你的进程有 30 分钟的 运行ning 时间,因为 PHP-FPM 和 Nginx 超时应该在 PHP 之后发生。
不要忘记客户端
如果您使用的是 AJAX 上传库,请同时检查其配置,因为它可能会对完整的 AJAX 上传请求施加另一个超时。
例如,dropzonejs 默认使用 30 秒超时。您的服务器可能会 运行 很长时间,但在这么短的时间之后,您的 javascript 库将终止连接。
通常您可以更改该值。使用 dropzone,您可以使用
设置 2100 秒的超时var myDropzone = new Dropzone("#uploader", {
// ...
timeout: "2100",
// ...
});
同样,使用比 Nginx 更高的值。
长运行宁任务:正确的方法
但是,你的方法又快又脏,即使我确定它适合你的情况,最好还是走另一条路:
- 不要在上传后立即进行 CSV 处理
- 相反,上传文件,将其放入队列中并通知客户稍后再回来查看
- 使用队列工作者在后台进行 CSV 处理
请查看有关队列的 Laravel 文档 (https://laravel.com/docs/5.5/queues)。
通过这种方法,您的用户将立即得到反馈,您将不会再遇到超时问题! (好吧,理论上:来自队列的后台作业也可以超时,但那是另一回事了。)
希望对您有所帮助:)