Question

We are running a PHP Daemon which look into a queue, receives worker jobs and spawns the worker to handle it. The workers themselves acquire a lock on a specific location before proceeding.

We spawn the Daemon as nohup background processes.

This entire architecture seems to work, except when we have to kill the processes, for whatever reason. If we kill them using -9, there is no way to trap it in the worker process and release the locks before dying.

If we use anything less than -9 (like TERM or HUP), it doesn't seem to be received by either the daemon or the worker processes.

Has anybody solved this problem in a better way?

(ps: BTW, Due to other considerations, we may not be able to change our language of implementation, so please only consider PHP based solutions)

Was it helpful?

Solution

I had related problems once too. Let me explain. I had a php 'daemon' that worked like a downloader. It accessed feeds periodically and downloads (laaaarge) content from the net. The daemon had to be stopped at a certain time, lets say 0500 in the morning to prevent it from using the whole bandwith during daytime. I decided to use a cronjob to send SIGTERM to the daemon at 0500.

In the daemon I had the following code:

pcntl_signal(SIGTERM, array($this, 'signal_handler'));

where signal_handler looked like this:

public function signal_handler($signal) {
    // some cleanup code 
    exit(1);
}

Unfortunately this did not work :|

It took me a time to find out what's going on. The first thing I figured out was that I'll have to call the method pcntl_signal_dispatch() on init to enable signal dispatching at all. Quote from the doc (comments):

If you are running PHP as CLI and as a "daemon" (i.e. in a loop), this function must be called in each loop to check if new signals are waiting dispatching.

Ok, so far, it seemed working. But I realized quickly that under certain conditions even this will not work as expected. Sometimes the daemon could only being stopped by kill -9 - as before. :|

So what's the problem?.. Answer: My program called wget to download the files via shell_exec. The problem is, that shell_exec() blocking waits until the child process has terminated. During this blocking wait no signal processing is done, the process can only being terminated using SIGKILL - what is hard. Also a problem was that child processes had to be terminated one by one as they became zombie processes after killing the father.

My solution to this was to execute the child process using proc_open() and the use stream_select() on it's output for non blocking IO.

Now it works like a charm. :) If you need further information don't hesitate to drop a comment.


Note If you are working with PHP < 5.3 then you'll have to use `

declare(ticks=1);

instead of pcntl_signal_dispatch(). You can rfer to the the documentation of pcntl_signal() for that. But if possible you should upgrade to PHP >= 5.3

OTHER TIPS

The problem was solved just by adding ticks:

// tick use required as of PHP 4.3.0
declare(ticks = 1);

Leaving this alone was causing my code not to work.

*(It's unfortunate that the documentation of pcntl_signal doesn't mention it in a lot more attention grabbing way.)*

You need to catch the signal (SIGTERM). This can be achieved via the function pcntl_signal. This will give you the option to perform any necessary functions before calling exit.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top