D
D
DarkKefir2020-04-28 22:40:10
PHP
DarkKefir, 2020-04-28 22:40:10

How to send a long PHP script to the background and at the same time return a message to the user about waiting for its execution?

Sources:

The site has a PHP script in which a rather long Ansible task is performed, according to the results of which a notification is sent to the user about the completed result and the browser is redirected to the desired page of the site.

Everything works and executes perfectly, but, of course, due to the long execution time, errors are displayed about the expiration of time, the so-called. timeouts.

On the server: nginx and PHP-FPM.
Used by Symphony.

PHP script:

use Symfony\Component\Process\Process;

$process = Process::fromShellCommandline("sudo /usr/bin/ansible-playbook -i {$inventoryFile}'");
$process->setTimeout(3600);

set_time_limit(0);

$process->run();

sleep(1);

return 'ok_response';


Taken the following:

In /etc/php/cli/php.ini :
max_execution_time = 0

In /etc/php/fpm/php.ini :
max_execution_time = 300

In /etc/nginx/nginx.conf :
keepalive_timeout  30;
keepalive_requests 1000;
reset_timedout_connection on;
client_header_timeout 30s;
client_body_timeout 30s;
send_timeout 15s;


For PHP-FPM:
fastcgi_read_timeout 300s;
fastcgi_send_timeout 300s;


Thus, I think that all timeouts are raised.

Also, an AJAX request was created in the user form. which, although it does not crash the 504 page itself with a gateway time-out error, nevertheless returns the site's message (in the form of a "red" notification) about the error - the script itself is executed successfully in the background.

The question is simple:
How to send the above piece of PHP script to be executed in the background, and return something to the user like: "Wait, everything will be soon"?
(Accordingly, after the execution of the PHP script, all the necessary notifications will be sent to it, which is happening now.)

Answer the question

In order to leave comments, you need to log in

4 answer(s)
S
Sergey, 2020-04-28
@KingstonKMS

Make a console worker that will execute tasks in order of priority.
1. Accept tasks or take some kind of database, such as a radish.
2. Do it.
3. Save notifications to the database.
4. Send a notification to the user.
This will allow you to process tasks in the console, in a queue, without creating the launch of several instances of scripts, for example, what happens through cron, notify the user when completed, the site will not need to be kept open and wait for execution.

N
Nurlan, 2020-04-28
@daager

Not the most beautiful, but the easiest way. you have NGinx - fastcgi_finish_request

K
Kirill Gorelov, 2020-04-29
@Kirill-Gorelov

There is another way, not the most technologically advanced, but the easiest.
Write the state to the database.
And update it if it has changed. And the user just show the status.
Fast, simple, reliable, but not cool ((

A
Andrey, 2020-04-30
@AndryG

In the code for such tasks I have a script 10 years ago written:

public static function execAsDeamon($script,$params = null){
    $tmp = '';
    foreach((array)$params as $k=>$v){
      if(empty($k)){
        continue;
      }
      $tmp .= ' -'.$k.'='.$v;
    }
    $tmp = g::options('core.php-cli-starter', 'php').' '.$script.' '.srv::$HOST_TYPE.$tmp.' > /dev/null &';
    exec($tmp);
  }

When heavy statistics on a resource are requested, but it has not yet been calculated, then I run the calculation script with this method, it does its work in a separate thread. and I give the client the page "oh, we need to wait a bit" with the page reload meta tag and the button "can't wait any longer. show statistics." to immediately reload the page.
Of course, there is a safeguard in the application logic against running the daemon multiple times.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question