tags:

views:

448

answers:

5

I am using pcntl_fork to start a child process to send an email via SMTP.

The child process uses the PEAR Mail package to send the email, but the trouble is if the remote server doesn't respond the process just runs forever waiting for a response, regardless of any time limit that is set in php.ini.

To get around this I'm using pcntl_alarm function to trigger a function after 30 seconds that kills the child process if it's still running.

function handlesig($sig) {
    global $pid,$node,$resend;
    posix_kill($pid,SIGKILL);
    mysql_query("insert into log (event) values ('Timed out!')");
}

When I kill the child process though I'm left with a defunct process on the system.

Is there a different signal I should use that will still force the child process to die without waiting for the connection (because the connection will never finish) and avoid a build up of defunct processes?

+1  A: 

The normal solution for this problem is useing a good configured local host relay. What i normaly do is setting up a local host releay useing postfix.

Then im gonna send the e-mail to the local relay, which queues it and send it to the recipient as soon as possible.

The good thing about sending it to the local relay is that you can configure it for bounce e-mails, and other answeres.

For you question about the defunct, as far as i know is the SIGKILL a very hard method for shuting down a process, did you try (SIGSTOP or SIGTSTP)?

The reason I am sending directly through PHP is so I can get the response and handle it appropriately for success/soft bounce/hard bounce. SIGTERM and SIGKILL are the only signals I know, and SIGTERM didn't work so I used SIGKILL. I will try SIGSTOP/SIGTSTP.
Tim
Hmm i personaly would do this in 2 seperate scripts. One for the sending through a local smtp service the secound for handling the bounce, a kind of automated pop/get script, which handles to bounces and success.One reason for this is that the php script which delivers the mail to the smtp is not blocking the web-server childs. For example if you have a maximum of 20 childs and every child is starting a connection to an external source no other service is available until a child is freed again.
A: 
exec(PATH_TO_PHP . " email_script.php $params > /dev/null 2>&1 &");

This way the parent is not waiting for a response from the child and you don't have a zombie. In the email_script.php handle your email sending and log the response to a file, which you can analyze from your parent script or what not.

agentile
+1  A: 

If you have zombie children, it means you're not waiting for them. Not a PHP expert, but the system call is waitpid(2). e.g. call

waitpid(-1, NULL, WNOHANG);

every now and then, or whenever you get SIGCHILD. Each call will reap up to one zombie. WNOHANG makes it returns right away instead of blocking if there are no exitted children.

The wait man page has a good notes section on how this all works...

Peter Cordes
A: 

To complet Peter anwser, take a look on http://www.php.net/manual/fr/function.pcntl-waitpid.php

Just need do that after the kill: pcntl_waitpid($pid)

Gonéri
+1  A: 

You need either wait for it as described above, or make the child process to detach from the parent using posix_setsid

StasM