У меня странная проблема, с которой я застрял пару дней назад.Я пытаюсь сгенерировать PDF в приложении Laravel, используя Chrome без головы, с помощью этой команды
google-chrome --headless --disable-gpu --print-to-pdf=outputfile.pdf http://localurl/pdf-html
Команда в основном открывает Chrome в режиме без головы, перемещается по заданному URL и печатает его как сохранение PDFфайл в указанном месте.Эта команда отлично работает при запуске в оболочке моей системы (я использую Ubuntu 18.04).Теперь моя проблема возникает при попытке запустить ту же команду с контроллера Laravel, я пробовал exec, shell_exec, system и passthru, и все они вызывают у меня одну и ту же проблему.Если я запускаю команду без перенаправления вывода и запуска процесса в фоновом режиме, добавляя >> tmpfile 2>&1 &
в конец команды, запрос зависает.Выполнение команды в фоновом режиме обычно не было бы проблемой, за исключением того, что мне нужно завершить команду, чтобы отправить файл обратно клиенту для загрузки.Запустив его в фоновом режиме, он в основном выполняет его асинхронно, и у меня нет никакого способа узнать, когда процесс завершается (или ждать, пока он не закончится), чтобы затем отправить файл в качестве загрузки для ответа.
I 'пробовал другие альтернативы безрезультатно.Я попытался использовать Process Symfony , который поставляется в комплекте с Laravel, но также не работает.Я попытался использовать puppeteer и вместо запуска команды google-chrome использовать скрипт node.js с кодом из документации puppeteer (который, кстати, также работает при запуске непосредственно в моей системной оболочке), нопри запуске из Laravel выдает исключение ошибки тайм-аута навигации.
Наконец, я создал простой php-файл со следующим кодом:
<?php
$chromeBinary = 'google-chrome';
$pdfRenderUrl = "http://localhost:8000/pdf-html";
$fileName = 'invoice.pdf';
$outputDirectory = "/path/to/my/file/" . $fileName;
$command = sprintf(
'%s --headless --disable-gpu --print-to-pdf=%s %s',
escapeshellarg($chromeBinary),
escapeshellarg($outputDirectory),
escapeshellarg($pdfRenderUrl)
);
exec( $command );
echo ( file_exists("/path/to/my/file/" . $fileName) ? 'TRUE' : 'FALSE');
?>
И код прекрасно работает при запуске из оболочки, как php thefile.php
печать ИСТИНА, означающая, что команда в exec была запущена и после ее завершения файл существует;и это именно тот код, который я использую в Laravel, за исключением того, что он работает только, как упомянуто выше, когда я отправляю процесс в фоновый режим.Кто-нибудь может подсказать мне здесь, пожалуйста?Спасибо
РЕДАКТИРОВАТЬ: @namoshek спасибо за быстрый ответ и извините, если я не прояснил себя.Проблема не в долгом времени ожидания, возможно, я мог бы жить с этим.Проблема в том, что exec никогда не завершается, и мне в конечном итоге приходится принудительно завершать процесс (ни exec, ни какая-либо другая альтернатива, они все навсегда замораживают запрос, за исключением Process, который завершается неудачей из-за исключения TimeoutException).Я использую почтальон для запроса конечной точки.Интерфейс - это приложение Angular, означающее, что запрос на загрузку счета будет в конечном итоге выполняться асинхронно.Кроме того, сама задача не является длительной задачей, поскольку, по сути, она заканчивается довольно быстро.Использование стратегии опроса или системы уведомлений, на мой взгляд, не представляется жизнеспособным решением.Представьте себе приложение с кнопкой загрузки, чтобы загрузить простой документ, и вам нужно нажать на кнопку и подождать, пока приложение уведомит вас по электронной почте (или другим способом) о том, что документ готов.Я мог бы понять это, если бы это был более сложный процесс, но загрузка документа кажется чем-то тривиальным.Но что меня смущает, так это то, что запуск задачи из сценария php работает так, как я хочу (синхронно), и я не могу воспроизвести поведение на контроллере laravel
EDIT: I 'Мы также пытались использовать BrowserShot , что, кстати, также не удается.Browsershot предоставляет способ взаимодействия, за кулисами с кукловодом, используя Process, и создание файла PDF.И хотя это внешняя программа, мне все еще кажется, что поведение, которое я получаю, не является нормальным, я должен быть в состоянии получить загрузку, даже если для выполнения запроса потребовалось 10 секунд, поскольку внешняя программа выполнялась синхронно.Но в моем случае это происходит из-за ошибки тайм-аута
РЕДАКТИРОВАТЬ: Итак, через некоторое время я столкнулся с очевидной причиной зависания сервера.Проблема в том, что я использовал сервер разработки Artisan.Изначально это не казалось мне проблемой, но кажется, что ремесленник не может справиться с такой нагрузкой.В функции, которую я реализую, я выполняю запрос к определенной конечной точке, назовем ее конечной точкой 1, чтобы сгенерировать pdf, код этой конечной точки запускает внешнюю команду, а при синхронном выполнении это означает код в конечной точке 1.ожидает завершения внешней команды.Внешняя команда, в свою очередь, должна перейти к конечной точке 2 на том же сервере, конечная точка 2 содержит представление html с содержимым, которое должно быть помещено в pdf, поскольку сервер все еще ожидает в конечной точке 1 возврата внешней команды, а затем в конечную точку.2 не отвечает, по-видимому, создает цикл, который сервер разработки ремесленника не может обработать.Проблема в том, что я сделал быстрый поиск и не нашел ничего, что указывало бы на неэффективность сервера разработки artisan.Я переместил среду в Apache только для проверки своей теории, и она сработала, хотя следует отметить, что выполнение запроса занимает очень много времени (около 10-20 секунд).Пока это кажется единственным разумным объяснением того, почему эта проблема происходила.Если кто-нибудь знает, как я могу улучшить производительность по этому запросу, или кто-то может дать лучшее объяснение первоначальной проблеме, я был бы признателен