skip to Main Content

I’m currently working on an internal website displaying a lot of statistics, and some pages or ajax scripts are extremely slow due to large datas.

What I’m searching is a way to launch theses scripts in background with a request, and then launch ajax requests to know the progress of the background script.

Is there any way to achieve this? I work with php7.0 and an apache2 server (I don’t have direct access to apache server configuration, so if it’s possible, I search for a client-side option)

2

Answers


  1. Chosen as BEST ANSWER

    If ever someone else is searching for a way to achieve this, here is the solution I found:

    I call in Ajax a script, it forks itself and save the PID of the child process in the database. Then I call session_write_close() in the child process to allow user making new requests, and the father process exits (not waiting for child end). As the father exits, the user receive an answer to his request, and the child process continue his job.

    Then in Ajax I call another script to get the evolution of the worker, and finally I get the result and kill the child process when everything is done.

    Here is the code of my worker class:

    class AsyncWorker
    {
        private $pid;
        private $worker;
    
        private $wMgr;
    
        public function __construct($action, $content, $params = NULL)
        {
            $this->wMgr   = new WorkersManager();
            $pid = pcntl_fork(); // Process Fork
            if ($pid < 0) {
                Ajax::Response(AJX_ERR, "Impossible de fork le processus");
            } else if ($pid == 0) { // In the child, we start the job and save the worker properties
                sleep(1);
                $this->pid    = getmypid();
                $this->worker = $this->wMgr->fetchBy(array("pid" => $this->pid));
                if (!$this->worker) {
                    $this->worker = $this->wMgr->getEmptyObject();
                    $this->wMgr->create($this->worker);
                }
                $this->worker->setPid($this->pid);
                $this->worker->setAction($action);
                $this->worker->setContent($content);
                $this->worker->setPercent(0.00);
                $this->worker->setResult("");
                $this->wMgr->update($this->worker);
                $this->launch($params);
            } else { // In the father, we save the pid to DB and answer the request.
                $this->worker = $this->wMgr->fetchBy(array("pid" => $this->pid));
                if (!$this->worker) {
                    $this->worker = $this->wMgr->getEmptyObject();
                    $this->worker->setPid($pid);
                    $this->wMgr->create($this->worker);
                }
                Ajax::Response(AJX_OK, "Worker started", $this->worker->getId());
            }
        }
    
        // Worker job
        private function launch($params = NULL)
        {
            global $form, $_PHPPATH, $url, $session;
            session_write_close(); // This is useful to let the user make new requests
            ob_start(); // Avoid writing anything
    
            /*
            ** Some stuff specific to my app (include the worker files, etc..)
            */            
    
            $result = ob_get_contents(); // Get the wrote things and save them to DB as result
            $this->worker->setResult($result);
            $this->worker->setPercent(100);
            ob_end_clean();
        }
    }
    

    It's a bit tricky but I had no choices, as I have no access to server plugins and libraries.


  2. you can make php script to execute shell bash script , or using exec() method for that

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search