Using pcntl_fork() can be a little tricky in some situations. For fast jobs, a child can finish processing before the parent process has executed some code related to the launching of the process. The parent can receive a signal before it's ready to handle the child process' status. To handle this scenario, I add an id to a "queue" of processes in the signal handler that need to be cleaned up if the parent process is not yet ready to handle them.<?phpdeclare(ticks=1);class JobDaemon{ public $maxProcesses = 25; protected $jobsStarted = 0; protected $currentJobs = array(); protected $signalQueue=array(); protected $parentPID; public function __construct(){ echo "constructed \n"; $this->parentPID = getmypid(); pcntl_signal(SIGCHLD, array($this, "childSignalHandler")); } public function run(){ echo "Running \n"; for($i=0; $i<10000; $i++){ $jobID = rand(0,10000000000000); $launched = $this->launchJob($jobID); } while(count($this->currentJobs)){ echo "Waiting for current jobs to finish... \n"; sleep(1); } } protected function launchJob($jobID){ $pid = pcntl_fork(); if($pid == -1){ error_log('Could not launch new job, exiting'); return false; } else if ($pid){ $this->currentJobs[$pid] = $jobID; if(isset($this->signalQueue[$pid])){ echo "found $pid in the signal queue, processing it now \n"; $this->childSignalHandler(SIGCHLD, $pid, $this->signalQueue[$pid]); unset($this->signalQueue[$pid]); } } else{ $exitStatus = 0; echo "Doing something fun in pid ".getmypid()."\n"; exit($exitStatus); } return true; } public function childSignalHandler($signo, $pid=null, $status=null){ if(!$pid){ $pid = pcntl_waitpid(-1, $status, WNOHANG); } while($pid > 0){ if($pid && isset($this->currentJobs[$pid])){ $exitCode = pcntl_wexitstatus($status); if($exitCode != 0){ echo "$pid exited with status ".$exitCode."\n"; } unset($this->currentJobs[$pid]); } else if($pid){ echo "..... Adding $pid to the signal queue ..... \n"; $this->signalQueue[$pid] = $status; } $pid = pcntl_waitpid(-1, $status, WNOHANG); } return true; }}