user1104854
user1104854

Reputation: 2167

pcntl_fork interfering with parent process

I'm working on a PHP app using a websocket, and I'm trying to essentially set up a timer. When the user arrives on a page, there's a 30 second waiting interval and a javascript timer is shown on their screen. Rather than relying on javascript to send a signal back once the countdown is complete (not to mention, the user tampering with the time), I'd rather have the server send a signal once those 30 seconds are up.

While the process in the fork is going on (a sleep function in this case) the user can send and receive messages through the websocket. However when the process in the fork is completed, if the user tries to perform any more actions that interact through the websocket they're disconnected and I can't figure out why.

It's something as simple as

//the user will be disconnected if they try to perform any actions after the sleep is finished
if(pcntl_fork()){
    sleep(30);
    $this->broadcast_message('done');
}
debug('after fork'); //this is displayed twice. Once as soon as it runs, and a second time when the sleep is done

The websocket disconnect only happens when I use pcntl_fork. The user isn't immediately disconnected. If the user tries to perform some other action that uses the websocket connection, they'll then be disconnected.

I know it's the pnctl_fork causing the issue, because I can sleep and then broadcast without using a fork and the user isn't disconnected, but then it holds up everything else and the user can't interact with the page anymore until sleep is finished.

//this works fine. However, this holds everything up and nothing further can be done so it's useless
sleep(30);
$this->broadcast_message('done');

Upvotes: 0

Views: 378

Answers (2)

William W
William W

Reputation: 1806

pcntl_fork returns 0 for the child and the PID for the parent. So it seems to me like you could have changed your initial if check to ensure it's being done on the child if(pcntl_fork() === 0){ and then call exit in the child when it's done. Then the parent process will never sleep or exit, but a message will still be sent after 30 seconds.

Modifying your initial code block:

if(pcntl_fork() === 0){
    sleep(30); // Child sleeping
    $this->broadcast_message('done');
    exit(0); // Child exits
}
// Only the parent gets here, and does so immediately
debug('after fork');

** I realize this question is very old and I can't promise this will work without knowing more about the websocket especially because things like file handles and databases get copied to the child during a fork, so closing in the child closes it in the parent. But I stumbled across this and wanted to provide me 2 cents since it seems odd to wait in the parent process and let the child process continue running code in an undefined way.

Upvotes: 1

user1104854
user1104854

Reputation: 2167

I figured out the problem. To anyone who has this same issue, the child process was not properly ending.

$pid = pcntl_fork();
if($pid){
    sleep(30);
    $this->broadcast_message('done');
    posix_kill($pid, SIGKILL);
}

Upvotes: 0

Related Questions