CodeIgniter Forums

Full Version: Execute a controller method in background.
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi,
     I have to execute controller method in background and I am using HMVC structure.
     
       <?php
          class Test_Controller extends CI_Controller  {
                public function index() {
                 }
                public function test() {
                      // background script code
                }
 
           } ?>


I need to execute the function test as background process using exec/shell command. Any solution?
If not,Where (folder structure) I can write background script in codeigniter?
It is possible to use exec() to spawn a new process and have it run asynchronously.
But... the process result must be piped to a null device.
You cannot expect exec to produce output and behave asynchronously.

I am not sure how HVMC might change this example. But here goes.

This is a controller to test the concept. It spawns two processes and echos index() method start and end times to the microsecond. You'll be able to see that index() runs very quickly.

PHP Code:
class Proc_test extends CI_Controller
{
 
   public function index()
 
   {
 
       echo "Proc_text::Index is called at ".$this->rightnow()."<br>";
 
       $param 5000000;
 
       $command "php ".FCPATH."index.php tools proc1 $param > /dev/null &";
 
       exec($command);
 
       $command "php ".FCPATH."index.php tools proc2 $param > /dev/null &";
 
       echo "Proc_text::Index is done at ".$this->rightnow()."<br>";
 
   }

 
   //a helper to give time of day with microseconds
 
   public function rightnow()
 
   {
 
       $time microtime(true);
 
       $micro_time sprintf("%06d", ($time floor($time)) * 1000000);
 
       $date = new DateTime(date('Y-m-d H:i:s.'.$micro_time$time));
 
       return $date->format("H:i:s.u");
 
   }


The guts are in this line.
PHP Code:
       $command "php ".FCPATH."index.php tools proc1 $param > /dev/null &"

It's basically a cli command which follows this form
   "php absolute/path/to/codeigniter/index.php controller method argument_1 argument_2 argument_n > pipe to null statement".

The "pipe to null" used here - "/dev/null &" - is the linux version. If your server is on Windows there is probably a similar construct but I don't know it. Without the "pipe to null" the process won't behave asynchronously.

This proof-of-concept uses a model to store execution durations in a table. It's included so we can prove that stuff really does happens in the background. Data will be written to the table several seconds after index() is done executing. It also proves we can use CI resources to do work - in this example use a model.

Here's the schema for the table

Code:
--
-- Table structure for table `test`
--

CREATE TABLE IF NOT EXISTS `test` (
 `id` int(11) NOT NULL,
 `proc1` float DEFAULT NULL,
 `proc2` float DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

-- add one empty row
INSERT INTO `test` (`id`) VALUES ('1');

Here's the model
PHP Code:
class ProcTimes extends CI_Model
{
 public function 
__construct()
 {
 
parent::__construct();
 
$this->load->database();
 }

 public function 
update($data)
 {
 
$this->db->update('test'$data);
 }


The actual processes are in a separate controller - Tools. They could be in the Proc_test class but in the interests of separation of concerns they are in one of their own.

Tools.php

PHP Code:
class Tools extends CI_Controller
{
 
   public function __construct()
 
   {
 
       parent::__construct();
 
       $this->load->database();
 
       $this->load->model('procTimes');
 
   }

 
   public function proc1($param 1)
 
   {
 
       if(is_cli()) //so this cannot be run from a browser
 
       {
 
           $time_start microtime(true);
 
           for($i 1$i $param$i++)
 
           {
 
               sqrt($i);
 
           }
 
           $time_end microtime(true);
 
           $time $time_end $time_start;
 
           $this->procTimes->update(['id' => 1'proc1' => $time]);
 
       }
 
   }

 
   public function proc2($param 1)
 
   {
 
       if(is_cli())
 
       {
 
           $time_start microtime(true);
 
           for($i 1$i $param$i++)
 
           {
 
               log10($i);
 
           }
 
           $time_end microtime(true);
 
           $time $time_end $time_start;
 
           $this->procTimes->update(['id' => 1'proc2' => $time]);
 
       }
 
   }


Basically we're executing some math routines a few million times (5 million as set in Proc_test::index() ) and calculating how much time it takes. The duration is stored in the database. You can browse to yoursite.com/proc_test and see it runs very quickly. If you have phpMyAdmin ready to view the test table in another browser tab you can quickly switch to it and, by repeatedly refreshing the display, see when the data is finally written. On my test platform it takes almost 5 seconds.

I just keep updating the same row in the table. But you could easily switch from 'update' to 'insert' if you wanted to. You'd want to make the `id`field auto increment if you did.

Hope this is adaptable to your needs.
(04-19-2017, 04:15 AM)saranayars Wrote: [ -> ]Hi,
     I have to execute controller method in background and I am using HMVC structure.
     
       <?php
          class Test_Controller extends CI_Controller  {
                public function index() {
                 }
                public function test() {
                      // background script code
                }
 
           } ?>


I need to execute the function test as background process using exec/shell command. Any solution?
If not,Where (folder structure) I  can write background script in codeigniter?

You need to trigger a background process execution, but you only think that it needs to be a controller method.
It shouldn't be.