runaction - Background actions

Hi,

can anybody explain me the functionality of the background actions of the extension ‘runactions’ in detail?

I havent got a clue to implement such a function generally.

In the documentation i could find just the following code which doesnt help me to understand whats going on.


public function actionTimeConsumingProcess()

    {

        if (ERunActions::runBackground())

        {

           //do all the stuff that should work in background

           //mail->send() ....

        }

        else

        {

            //this code will be executed immediately

            //echo 'Time-consuming process has been started'

            //user->setFlash ...render ... redirect,

        }

    }

Where should i put this function? Within my controller? In the next step i thought i simply call the function normally. But obviously i was wrong:-) nothing happend and only the else part was executed. So in my next attempt i call my function with the help of:


ERunActions::runAction('bookmark/TimeConsumingProcess',$params=array(),$ignoreFilters=true,$ignoreBeforeAfterAction=true,$logOutput=false,$silent=false);

but…nothing happend. Although the false part has been executed again.

so, i gave this method a chance


ERunActions::touchUrlExt($url,$postData=null,$contentType=null,$httpClientConfig=array());



which should triggered my background job code in the if part. But in this case nothing happened at all. Even the else part has been omitted.

So, as you guess, my proramming skills are really far away from average:-)

Can anybody help me to explain me the basic functionality of this extension when i’m going to execute code in the background.

sorry for my bad english. thanks for any advice.

greets

Thorsten

Sorry for my broken english ,but i have to say that i have the same questiones.

I tested ERunActions::touchUrl(),but nothing is happend.

Then i tested RunActionsController::actionTouch() and with a corn.php return an array ,it works,but used ERunActions::TYPE_ACTION

You can use ERunActions::runBackground() - as described - in a controller action.

Try this for testing - slightly modified comparing to documentation:




public function actionIndex()

    {

        if (ERunActions::runBackground())

        {

           Yii::log('Starting background task...');


           //... time-consuming code here

           

           //Inform the user if 'hasFlash' is implemented in all views

           //Yii::app()->user->setFlash('runbackground','Process finished');


           Yii::log('Background task executed');

           Yii::app()->end(); 

        }

       

           //the stuff you normally would do 

           //for example:

           $this->render('index');

    

    }



Check the runtime/application.log to see if the background code was executed.

Check the source to understand, what happens when ERunActions::runBackground

When the user calls the controller actionIndex,

the same url will be ‘touched’ internally to execute the background part.

When using ERunActions::touchUrl(‘http://www.yiiframework.com’) a request will be sent to this webserver, nothing more happens, you can’t see anything, because touchUrl doesn’t care about what this host is doing to handle the request, doesn’t care about the data the webserver will send after the request.

The only thing that happend is, that the ‘touched’ host will start working, will do something, but your code is not interested in what really happens.

So this can be useful for transfering data between webservers. When a url is ‘touched’ the webserver can post data to another (or the requesting) host (using EHttpClient at the other host):

  • When you call the action url in your browser you maybe have to wait minutes until the work ist done: collecting/preparing data, send …

  • By using ‘touchUrl’ the client will not wait until the process is finished.

And it’s useful for ERunActions::runBackground() to start asynchronous ‘background’ tasks at the own webserver.

Thank you for your help. It’s real worked.

There are still a question:

When i used touchUrl() in another action ,nothing has happened but waitting for the respond.

Because of the timeout setting in the request()?


   //in action index,maybe i should't do this 

   ERunActions::touchUrl($this->createUrl('site/timeConsumingProcess'));

Where and when i could use this method(ERunActions::touchUrl) ?

You have to use createAbsoluteUrl() instead of createUrl(), because touchUrl only works with full specified urls.

Note: I have updated the extension to version 1.1

Thanks a lot! It’s indeed a useful extension. :lol:

Will this run on Windows under a WAMP server?

Yes, it will.

It’s developed under Win 7, Apache 2.2, PHP 5.3.

I just could not get this working. My problem is effectively the same as the OP in this thread, where the action called with runBackground only ever returned false, and never ran the code that should work in the background.

This was the case with WAMP Server on WinXP, Apache 2.n, and PHP 5.n.

I also uploaded to a Debian Linux server, and still no dice. The runBackground function was called, returned false, and never retouched the action.

I traced through the code and everything executed without error. The client->request function returned via the successful path, but still the background thread never executed.

After many hours I gave up and used the php exec function to run a bash script in the background, that called the PHP script to do the processing.

See my comment at runactions

Hi Joblo

I’m really interested in your extension, it describes precisly what I need

but I run into the same thing as the others

here is my controller , any idea why ERunActions::runBackground() is always false ?




public function actionTest (){

        if (ERunActions::runBackground())

        {

           Yii::log('Starting background task...', CLogger::LEVEL_WARNING, 'CronController');

           //ERunActions::touchUrl($this->createAbsoluteUrl('/cron/talk'),$postData=null,$contentType=null);

            Yii::app()->user->setFlash('runbackground','Process finished');

           Yii::log('Background task executed', CLogger::LEVEL_WARNING, 'CronController');

           Yii::app()->end(); 

        }

       

          echo "<br/>do this now";

    }



I’ve tried many different possibilities from your doc , but I must admit

It’s a bit missleading to have documentation in different locations

is the main documentation wrong ?

That’s what I seem to understand from the comments ?

but can’t get it to work :(

If you debug the code above, ERunActions::runBackground() will always return false.

This is ok, because the code below


echo "<br/>do this now";

should be executed immediatly.

But what happens, is that the httpclient does a second call to actionTest by ERunActions::touchUrl. If the url is ‘touched’ the method ERunActions::runBackground() returns true and the code inside the runBackground block will be executed.

But this happens in another ‘thread’ you are not debugging.

But what’s the problem?

If you can’t find a log item ensure that you have enabled the level ‘CronController’ in you log config.

Try with a simple code first and check if there is a log item.




public function actionTest ()

{

        Yii::import('ext.runactions.components.ERunActions');


        if (ERunActions::runBackground())

        {

           Yii::log('running in Background',CLogger::LEVEL_ERROR);

           Yii::app()->end(); 

        }

       

        echo "<br/>do this now";

}



or this




public function actionTest ()

{

        Yii::import('ext.runactions.components.ERunActions');


        if (ERunActions::runBackground())

        {

           Yii::log('running in Background',CLogger::LEVEL_ERROR);

        }

        else

          echo "<br/>do this now";

}



Is it possible that the controller’s filter function isn’t allowing runBackground() to touch the current controller’s action without having that second thread log in?

If so, is it possible to pass runBackground() the Session info that Yii is looking for or is it impossible for runbackground() to work on actions that are restricted to authenticated users?

Hello, I try to send some emails inside the controllers and for a reason it doesn’t work because of the GET POST vars. In general when we want to send emails then this process some times takes time so with background action works perfect, the issue is what we can do when we want to do it inside a controller.

runactions should submit GET/POST vars too.

Take a look at this comment , maybe that’s the problem.

Did you try to use it with the ehttpclient extension?

Hi Joblo, I tried adding this test action to my controller:




public function actionTest ()

{

        Yii::import('ext.runactions.components.ERunActions');


        if (ERunActions::runBackground())

        {

           Yii::log('running in Background',CLogger::LEVEL_ERROR);

        }

        else

          echo "<br/>do this now";

}



but the runBackground block is still not being executed since I can’t find the entry in the application.log file. Is there anything that I’m missing? I have version 1.1 in my extensions folder. Much thanks! This extension will be very useful!!

I tried this and it doesn’t save anything in database




    public function actionTest(){

        if (ERunActions::runBackground())

        {

            Yii::log('Running actionTest in Background',CLogger::LEVEL_ERROR);

            Yii::app()->db->createCommand()->insert('test', array(

                    'temp' => 'NULL',

            ));

            Yii::app()->end();

        }

        

        echo "Do this now";

        

    }



I also tried and i get no data in db




ERunActions::runAction('mycontroller/test');

public function actionTest(){

            Yii::app()->db->createCommand()->insert('test', array(

                    'temp' => 'NULL',

            ));

    }



I dont see any issue or problem in my code, what i’m missing?

Hi all, i am just getting crazy trying to make this to work. it would only work if I uses the last value in $notif but what i need is to get from db the boolean make it through the if and finally send the message. It just doen’t go through the “if” if value is true. Does anyone know how to make this to work? Thanks a lot…

        &#036;notif=(int)&#036;userdb-&gt;notif; // notif is a boolean but it doesnt work


        &#036;notif=(bool)&#036;userdb-&gt;notif; // notif is a boolean but it doesnt work


       &#036;notif=(boolean)&#036;userdb-&gt;notif; // notif is a boolean but it doesnt work

Yii::import(‘ext.runactions.components.ERunActions’);

if(ERunActions::runBackground()){

        &#036;notif=(int)&#036;userdb-&gt;notif; // notif is a boolean but it doesnt work


        &#036;notif=(bool)&#036;userdb-&gt;notif; // notif is a boolean but it doesnt work


       &#036;notif=(boolean)&#036;userdb-&gt;notif; // notif is a boolean but it doesnt work


       &#036;notif=true; // this is the only way it would work, it would go through the following if,  but what i need is other previous options. Also tested ouside  


        if(&#036;notif){

// it just doesnt executes only if i assign $notif=true directly…

            &#036;deviceToken=7A2xxxxxxxxxxxxxxxxxxxxxxxx3B'xxxxxxxxxxxx;


            &#036;message='New User Bla Bla Bla';


            &#036;badge=1;


            Yii::app()-&gt;getModule('myapns')-&gt;startConnection();


            Yii::app()-&gt;getModule('myapns')-&gt;createMessage(&#036;deviceToken,&#036;message,&#036;badge);


            Yii::app()-&gt;getModule('myapns')-&gt;closeConnection();

}

}

For those of you who couldn’t get runactions to work, perhaps I’m able to shed some light (I learnt it the hard way though). As Joblo has pointed out in his #12 post, ERunActions::runBackground() will always return false. Only after that, ERunActionsHttpClient will automatically do a second call to the same url (Controller Function) where the ERunActions::runBackground() block resides using ERunActions::touchUrl. This time, ERunActions::runBackground() will return true and executes the intended codes in a separate ‘thread’.

However, the url is ‘touched’ by ERunActionsHttpClient under an Unauthenticated User role. So, if the url in question can only be accessed by Authenticated Users, ERunActionsHttpClient will be redirected to the login screen. The intended codes didn’t execute because the call was being redirected to the login screen on a different ‘thread’ which you can’t see and led you to think that the entire thing is broken at best.

In order for it to work, ERunActionsHttpClient will have to be passed the cookie which holds the session ID (assuming you’re using cookie to preserve session). In ERunActions.php, for the function touchUrl, replace the last line


$client->request($host,$port,$uri,$verb,$urlParams,$postData,$contentType);

with


$client->request($host,$port,$uri,$verb,$urlParams,$postData,$contentType,array('PHPSESSID'=>$_COOKIE['PHPSESSID']));

Replace ‘PHPSESSID’ with whatever the session cookie is named. The above changes will perhaps solve your problem. You can modify the codes above so that it is more reusable by making the cookie into a parameter.

Anyway, I found out even if it works, the background ‘thread’ that is running the time consuming codes will block off all incoming request until it had finished executing. You can try this by doing a


sleep(60)

in the background ‘thread’ to simulate a long running process (like generating a report). Although, the foreground ‘thread’ will be immediately returned to your control, try visiting other pages in the same website. You will find that it will hang there and not responding until the background ‘thread’ has finished processing.

How can I call these by ajax call?