7 The reason for the MySQL "Lost Connection during query" issue when forking is the fact that the child process inherits the parent's database connection. When the child exits, the connection is closed. If the parent is performing a query at this very moment, it is doing it on an already closed connection, hence the error.
9 An easy way to avoid this is to create a new database connection in parent immediately after forking. Don't forget to force a new connection by passing true in the 4th argument of mysql_connect():
20 // parent process - regenerate our connections in case the kid kills them
21 @include(".htconfig.php");
22 $db = new dba($db_host, $db_user, $db_pass, $db_data, $install);
23 unset($db_host, $db_user, $db_pass, $db_data);
24 session_write_close();
30 // Do something with the inherited connection here
31 // It will get closed upon exit
36 If you want to execute some code after your php page has been returned to the user. Try something like this -
42 posix_kill(posix_getpid(), SIGHUP);
45 // Do some initial processing
49 // Switch over to daemon mode.
51 if ($pid = pcntl_fork())
54 ob_end_clean(); // Discard the output buffer and close
56 fclose(STDIN); // Close all of the standard
57 fclose(STDOUT); // file descriptors as we
58 fclose(STDERR); // are running as a daemon.
60 register_shutdown_function('shutdown');
62 if (posix_setsid() < 0)
65 if ($pid = pcntl_fork())
68 // Now running as a daemon. This process will even survive
73 $fp = fopen("/tmp/sdf123", "w");
74 fprintf($fp, "PID = %s\n", posix_getpid());
81 while(count($this->currentJobs) >= $this->maxProcesses){
82 echo "Maximum children allowed, waiting...\n";
85 duerra at yahoo dot com
87 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.
89 I am including a stripped down version of a job daemon that should get a person on the right track.
93 //A very basic job daemon that you can extend to your needs.
96 public $maxProcesses = 25;
97 protected $jobsStarted = 0;
98 protected $currentJobs = array();
99 protected $signalQueue=array();
100 protected $parentPID;
102 public function __construct(){
103 echo "constructed \n";
104 $this->parentPID = getmypid();
105 pcntl_signal(SIGCHLD, array($this, "childSignalHandler"));
111 public function run(){
113 for($i=0; $i<10000; $i++){
114 $jobID = rand(0,10000000000000);
115 $launched = $this->launchJob($jobID);
118 //Wait for child processes to finish before exiting here
119 while(count($this->currentJobs)){
120 echo "Waiting for current jobs to finish... \n";
126 * Launch a job from the job queue
128 protected function launchJob($jobID){
131 //Problem launching the job
132 error_log('Could not launch new job, exiting');
137 // Sometimes you can receive a signal to the childSignalHandler function before this code executes if
138 // the child script executes quickly enough!
140 $this->currentJobs[$pid] = $jobID;
142 // In the event that a signal for this pid was caught before we get here, it will be in our signalQueue array
143 // So let's go ahead and process it now as if we'd just received the signal
144 if(isset($this->signalQueue[$pid])){
145 echo "found $pid in the signal queue, processing it now \n";
146 $this->childSignalHandler(SIGCHLD, $pid, $this->signalQueue[$pid]);
147 unset($this->signalQueue[$pid]);
151 //Forked child, do your deeds....
152 $exitStatus = 0; //Error code if you need to or whatever
153 echo "Doing something fun in pid ".getmypid()."\n";
159 public function childSignalHandler($signo, $pid=null, $status=null){
161 //If no pid is provided, that means we're getting the signal from the system. Let's figure out
162 //which child process ended
164 $pid = pcntl_waitpid(-1, $status, WNOHANG);
167 //Make sure we get all of the exited children
169 if($pid && isset($this->currentJobs[$pid])){
170 $exitCode = pcntl_wexitstatus($status);
172 echo "$pid exited with status ".$exitCode."\n";
174 unset($this->currentJobs[$pid]);
177 //Oh no, our job has finished before this parent process could even note that it had been launched!
178 //Let's make note of it and handle it when the parent process is ready for it
179 echo "..... Adding $pid to the signal queue ..... \n";
180 $this->signalQueue[$pid] = $status;
182 $pid = pcntl_waitpid(-1, $status, WNOHANG);
194 function notifier(&$a,$item_id,$parent_id) {
199 notice("Failed to launch background notifier." . EOL );
204 // parent process - regenerate our connections in case the kid kills them
206 @include(".htconfig.php");
207 $db = new dba($db_host, $db_user, $db_pass, $db_data, $install);
208 unset($db_host, $db_user, $db_pass, $db_data);
209 session_write_close();
212 // go back and finish the page
220 // if not parent, fetch it
224 // expand list of recipients
226 // grab the contact records
230 // if no dfrn-id continue
232 // fetch_url dfrn-notify