Console application in background

Hello all,

After the register proccess I’m sending an email with the activation code, but the sent takes 5 o 10 seconds that the user is waiting until it has been sent. I would like to send the mail (the process that sends the mail is writen in php) in background when the Yii action of register finish and avoid the user to be waiting.

For this reason, I have created a command to send the mail that I launch with the entryScript as described in the guide.

At this point I have 2 problems:

  • The first one is that the content of the mail to sent is not possible to pass as an argument to the command because it’s too large and with blank spaces and double and simple quotes (the mail content is html).

  • The second one is that in windows I cannot execute it in background, I have tested with this code but without success.


public static function execCommandInBackground($cmd) {

        $cmd = "php " . Yii::getPathOfAlias("application.consoleScript") . ".php " . $cmd;

        if (substr(php_uname(), 0, 7) == "Windows"){

            pclose(popen("start /B ". $cmd, "r"));

            //exec("start /B ". $cmd);

        } else {

            exec($cmd . " > /dev/null &");

        }

    }

I’m new in php and Yii, and I’m not sure whats the best practice to do this but I understand it shouldn’t be too complicated, all the platforms do it. I have seen that in Zend there is something similar to job tasks to execute in background but I didn’t find in Yii. Is there something similar? Can anyone help me?

Maybe, thereis one simpler solution, I would be pleased if someone could help me.

Thank you very much.

Regards:

Kike

You could:

  • Use a DB table as "outgoing email queue" with fields like sender, recipient, content, sendstatus, etc.

  • Create a yiic command to process that queue (send email and update status field)

  • Run this command every minute from cron (or some windows task scheduler)

Thank you Mike,

Is there some way to launch a background proccess from a php script better than a cron task running each minute, the user won’t have so quickly response from the service than in other platforms and I think it’s not very efficient.

Thank you very much for your help.

Regards

Lole

I once did some research on this. The result was: If you want a solid & simple solution, don’t do it ;). Try to google for “PHP process fork” for more information.

Thanks Mike,

At the end I’m using the Yii command feature, to pass the content of the mail through ommand line I encode the html, remove the ‘\n’, and in the command I decode the html.

To launch in background I use this method, is working in Windows, but still is not tested in Linux (I expect it works without problems).


if (substr(php_uname(), 0, 7) == "Windows"){

            $WshShell = new COM("WScript.Shell");

            $oExec = $WshShell->Run("cmd /C " . $cmd, 0, false);

        } else {

            exec($cmd . " > /dev/null &");

        }

I hope, it can be useful for all. :D

Kike

COM is a Windows only extension. And i’d really be very careful with starting a new process on every web request to send emails. You have to make very sure, that you don’t end up with 1000s of processes hanging around on your machine if the children don’t terminate correctly (and some evil person is bombing you). That’s why most professional sites use the queue approach with an external process that handles sending the mails.

So you have been warned ;)

EDIT: I now see, your linux solution doesn’t use COM. The concerns above still apply though.

Thanks Mike,

Windows is only for local development environment. The production environment is in Linux.

Kike

The popen way works for me on Windows. I created email model. Then I do:




$email = new Email;

$email->to = '...';

$email->subject = '...';

$email->message = '...';

$email->save(false);


Helper::runConsoleCommand('sendEmails');



The actual yii console command uses mutex extension, so there’s always only 1 instance running/working. The console command loops through all email models, sends each mail + deletes the model and then exits. Easy to build in priority system as well (eg when sending newsletter to 1000 guys, you want to make sure a signup/lost-password email gets send asap).

I would suggest using a job queue such as gearman. This will scale better.

yii Mutex extension is useful , both job queue and cron task will be ok for background job :lol: