У меня были большие проблемы с получением пакета Laravel Excel для экспорта большого количества данных. Мне нужно экспортировать около 80-100 тыс. Строк, поэтому я реализовал экспорт из очереди , как указано в документации . Он отлично работает, когда я экспортирую меньшее количество строк, но когда я пытаюсь сделать 60-80 тыс. Строк, каждый раз происходит сбой. Во время обработки заданий я наблюдаю созданный временный файл и вижу, что размер файла увеличивается. Я также наблюдаю за заданиями в базе данных (я использую драйвер очереди базы данных) и вижу, что задания завершаются на некоторое время. Кажется, что задания занимают все больше времени, пока работа не сработает. Я не понимаю, почему первые несколько заданий выполняются быстро, а затем они начинают занимать все больше и больше времени.
Я использую supervisor для управления очередью, поэтому вот мой конфиг для этого:
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/site/artisan queue:work --sleep=3 --tries=3 --timeout=120 --queue=exports,default
autostart=true
autorestart=true
user=www-data
numprocs=8
redirect_stderr=true
stdout_logfile=/var/log/supervisor/worker.log
loglevel=debug
А потом мой контроллер для создания экспорта
(new NewExport($client, $year))->queue('public/exports/' . $name)->allOnQueue('exports')->chain([
new NotifyUserOfCompletedExport($request->user(), $name),
]);
Я использую:
Laravel 5.8, PHP 7.2, Postgresql 10.10
Я должен также упомянуть, что я немного поиграл с размером чанка, но в конце я всегда сталкивался с одной и той же проблемой. Я пробовал куски размером 500, 2000, 10000, но не повезло.
В таблице failed_jobs исключение составляет MaxAttemptsExceededException
, хотя у меня также есть исключения для InvalidArgumentException File '/path/to/temp/file' does not exist
. Я не совсем уверен, что еще делать. Я думаю, я мог бы сделать это так, чтобы не было времени ожидания, но похоже, что это только вызовет больше проблем. Любая помощь будет оценена.
РЕДАКТИРОВАТЬ
Вот содержание моего класса экспорта:
class NewExport implements FromQuery, WithHeadings, WithMapping, WithStrictNullComparison
{
public function __construct($client, $year)
{
$this->year = $year;
$this->client = $client;
}
public function query()
{
$data = $this->getDataQuery();
return $data ;
}
public function headings(): array
{
$columns = [
//....
];
return $columns;
}
public function map($row): array
{
$mapping = [];
foreach($row as $key => $value) {
if(is_bool($value)) {
if($value) {
$mapping[$key] = "Yes";
} else {
$mapping[$key] = "No";
}
}else{
$mapping[$key] = $value;
}
}
return $mapping;
}
private function getDataQuery()
{
$query = \DB::table('my_table')->orderBy('my_field');
return $query;
}
Класс NotifyUserOfCompletedExport
просто создает работу, чтобы отправить по электронной почте вошел в систему пользователя, что экспорт завершен со ссылкой для его загрузки.
class NotifyUserOfCompletedExport implements ShouldQueue
{
use Queueable, SerializesModels;
public $user;
public $filename;
public function __construct(User $user, $filename)
{
$this->user = $user;
$this->filename = $filename;
}
public function handle()
{
// This just sends the email
$this->user->notify(new ExportReady($this->filename, $this->user));
}
}
РЕДАКТИРОВАТЬ 2:
Итак, я прочитал этот пост , и я убедился, что со временем на моем сервере просто не хватает памяти. Это приводит к ошибке MaxAttemptsExceededException
. Я добавил больше памяти на сервер, и я все еще получаю InvalidArgumentException File '/path/to/temp/file' does not exist
после выполнения заданий. Это даже более странно, потому что я вижу, что / path / to / temp / file на самом деле существует . Так что я понятия не имею, что здесь происходит, но это супер расстраивает.