Как запустить php скрипт в фоне?
Есть кнопка на странице по нажатию на которой надо чтобы пользователь мог дальше продолжать работу, пока в фоне происходит выполнение скрипта.
Это реализовано путем открытия новой вкладки по нажатию на кнопку, в которой выполняется скрипт, а по завершении вкладка закрывается.
Но я столкнулся с проблемой, что выполнение скрипта может быть довольно долгим и по истечении 60с таймаута nginx принудительно завершает выполнение скрипта. Повышать таймаут не вариант.
Как сделать так, чтобы скрипт выполнялся в фоне?
Дополнительно:
Как вариант это очередь + крон. Пользователь нажимает кнопку, записывается задание, пусть даже в файл, крон дергает скрипт на проверку заданий, выполняет и удаляет файл
по истечении 60с таймаута nginx принудительно завершает выполнение скрипта
Nginx завершать скрипт не может и не делает этого. Он просто перестаёт ждать от него ответа, но сам скрипт при этом продолжает выполняться, если внутри него самого или условного FPM нет другого таймаута.
nohup php file.php 1231 12312 12321 234234 vasya > /dev/null 2>&1 & |
nohup php file.php 1231 12312 12321 234234 vasya > /dev/null 2>&1 &
Более того, есть сомнения что у воркера fpm будет достаточно прав в системе, чтобы дернуть эту команду.
Первый комментарий в ветке даёт самое верное решение - кинуть в очередь и обработать правильно запущенным скриптом.
Однако судя по постановке вопроса - мой вариант автором может быть реализован, а вариант даже с очередью в данный момент вряд ли. Если бы вы при этом просто написали что стоит задуматься об экранировании данных - я бы с вами согласился на все 100%, ибо как то считаю это естественным - а тут стоило бы действительно указать. зря вы начали эти игры в пилу.
З.Ы. Какую команду? nohup?
з.ы. вызов php или чего-либо еще, а может и exec оказаться в disable_functions.
з.ы. и при этом человеку дадут поставить какой нибудь rabbitmq, что бы с очередями играться? ну такое себе предположение.
Ответы:
Как отдать ответ клиенту и продолжить выполнение долгого скрипта?
или так.
<?php ignore_user_abort(true); set_time_limit(0); ob_start(); header('Connection: close'); header('Content-Length: '.ob_get_length()); // можно добавить http статус подходящий ob_end_flush(); ob_flush(); flush(); // дальше запуск run_havy_task(); |
<?php ignore_user_abort(true); set_time_limit(0); ob_start(); header('Connection: close'); header('Content-Length: '.ob_get_length()); // можно добавить http статус подходящий ob_end_flush(); ob_flush(); flush(); // дальше запуск run_havy_task();
оба варианта предполагают, что есть отдельный способ получения результатов выполнения запущенной задачи.
UPD: после критики в комментариях, поясню.
Предложенное мной решение - примитивный способ сказать web серверу вернуть клиенту ответ и после этого продолжить выполнение скрипта.
При этом ресурсы ресурсы сервера не будут освобождены пока функция run_havy_task не закончит работу. Можно использовать fastcgi_finish_request - но она не на 100% гарантирует завершение процессов.
Таким образом, если до этого вы не переживали о ресурсах выделенных на выполнение "тяжелого" скрипта, то можно продолжать и так - запихнуть всё тяжелое в внутрь run_havy_task.
Но лучше будет "тяжелую" часть обрабатывать в отдельных процессах. Например, одним из способов из комментариев к вопросу или из другого ответа, ссылку на который я дал в начале своего.
- Ну вы бы хоть какой нибудь fastcgi_finish_request добавили что бы не ждать таймаута.
Ну и решение так себе - забрать под себя процесс php-fpm.
- Дмитрий, run_havy_task_and_release_fpm();
- iljaGolubev, это как вы release_fpm будете делать? Воркер nginx то вы через finish отправите других обслуживать, а с fpm вы в этой конструкции как это сделаете?
- да что хотите, то и делайте. не моя функция.
вопрос Как запустить php скрипт в фоне? - ответ. - iljaGolubev, это не запустить процесс в фоне. это продолжить юзать процессы fpm пока вы не выжрете весь пул fpm и nginx будет весело отвечать всем новым 502. А без finish_request это еще выжрать всех воркеров nginx. Такой вариант убийства сервера без регистраций и смс
- Дмитрий,
fastcgi_finish_request — Flushes all response data to the client
///
ob_end_flush();
ob_flush();
flush();я не на 100% уверен, что это одно и тоже. а вы?
- iljaGolubev, стоит внимательно прочитать документацию помимо того что finish делает flush она еще и закрывает request сервера который обращается к fpm. Говорит ему финита ля комедия - иди работай с другими.
and finishes the request. This allows for time consuming tasks to be performed without leaving the connection to the client open.
В вашем случае - nginx будет сидеть ждать когда у него таймаут на ожидание сработает.
-
run_havy_task(){ // exec nohup // rabbit // wtf exit(0); }
run_havy_task(){ // exec nohup // rabbit // wtf exit(0); }
- iljaGolubev, и? пока run_havy_task не будет выполнена - до exit ни хрена не дойдет. И процесс php-fpm будет этим заниматься. Вы через chatgpt что ли варианты ищете?
- Дмитрий,
вы и правда не понимаете ?
run_havy_task(){ exit(0); }
всё. выполнена. в чем проблема то? вопрос бы не в том как не повесить сервер при "долгих" скриптах, а как не нарваться на истечение таймаута от nginx не меняя его. - iljaGolubev, нет не понимаю. такой конструкции в php нет. я предположил что вы опечатались - но судя по всему нет.
вопрос как выполнить скрипт в фоне. ваше решение не решение в фоне. ваше решение - а давайте грохнем сервак. ну вообщем то почему нет - нахрен он нужен
- Дмитрий, ну а я вас не понимаю.
Автор:
Это реализовано путем открытия новой вкладки по нажатию на кнопку, в которой выполняется скрипт, а по завершении вкладка закрывается.
Дмитрий:
а давайте грохнем сервак. ну вообщем то почему нет - нахрен он нужен
Я: а пофиг!
- iljaGolubev, ну вот стоит в верху вашего решения и дописать "а давайте грохнем сервак ибо мне пох". Тогда решение примет законченый вид, и глядишь автор вопроса посмотрит на другие решение которые ему в комментах посоветовали.
- iljaGolubev, тупой ответ.
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
Для запуска PHP скрипта в фоне существует несколько способов, в зависимости от того, какой именно функционал вам необходим. Ниже приведены несколько способов, которые могут помочь вам достичь этой цели:
1. Использование командной строки:
Вы можете запустить PHP скрипт в фоне, используя команду `php` в терминале и добавив амперсанд `&` в конце команды. Например:
php script.php &
2. Использование функции `exec`:
Вы также можете использовать функцию `exec` в PHP для запуска скрипта в фоне. Например:
exec('php script.php > /dev/null 2>&1 &');
3. Использование `nohup`:
`nohup` - это утилита, которая позволяет запустить процесс в фоне и не зависеть от текущего терминала. Например:
nohup php script.php > /dev/null 2>&1 &
4. Использование `screen`:
`screen` - это утилита, которая позволяет создавать виртуальные терминалы в Linux. Вы можете запустить скрипт в фоне в новом экране. Например:
screen -S myscript php script.php
Выберите подходящий для вас способ в зависимости от ваших потребностей и требований к процессу запуска PHP скрипта в фоне.