]> git.mxchange.org Git - friendica.git/blob - include/notifier.php
0beb72cd0e76e0725cb718a452262cabcbd712b1
[friendica.git] / include / notifier.php
1 <?php
2
3
4
5
6 /*
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.
8
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():
10
11
12
13
14 $pid = pcntl_fork();
15             
16 if ( $pid == -1 ) {       
17     // Fork failed           
18     exit(1);
19 } else if ( $pid ) {
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();
25         session_start();
26
27         return;
28 } else {
29     // We are the child
30     // Do something with the inherited connection here
31     // It will get closed upon exit
32     exit(0);
33 ?>
34
35
36 If you want to execute some code after your php page has been returned to the user. Try something like this -
37
38 <?php
39 function index()
40 {
41         function shutdown() {
42             posix_kill(posix_getpid(), SIGHUP);
43         }
44
45         // Do some initial processing
46
47         echo("Hello World");
48
49         // Switch over to daemon mode.
50
51         if ($pid = pcntl_fork())
52             return;     // Parent
53
54         ob_end_clean(); // Discard the output buffer and close
55
56         fclose(STDIN);  // Close all of the standard
57         fclose(STDOUT); // file descriptors as we
58         fclose(STDERR); // are running as a daemon.
59
60         register_shutdown_function('shutdown');
61
62         if (posix_setsid() < 0)
63             return;
64
65         if ($pid = pcntl_fork())
66             return;     // Parent
67
68         // Now running as a daemon. This process will even survive
69         // an apachectl stop.
70
71         sleep(10);
72
73         $fp = fopen("/tmp/sdf123", "w");
74         fprintf($fp, "PID = %s\n", posix_getpid());
75         fclose($fp);
76
77         return;
78 }
79 ?>
80
81 while(count($this->currentJobs) >= $this->maxProcesses){
82     echo "Maximum children allowed, waiting...\n";
83     sleep(1);
84 }
85 duerra at yahoo dot com
86 02-Jul-2010 02:06
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. 
88
89 I am including a stripped down version of a job daemon that should get a person on the right track.
90
91 <?php
92 declare(ticks=1);
93 //A very basic job daemon that you can extend to your needs.
94 class JobDaemon{
95
96     public $maxProcesses = 25;
97     protected $jobsStarted = 0;
98     protected $currentJobs = array();
99     protected $signalQueue=array();  
100     protected $parentPID;
101   
102     public function __construct(){
103         echo "constructed \n";
104         $this->parentPID = getmypid();
105         pcntl_signal(SIGCHLD, array($this, "childSignalHandler"));
106     }
107   
108     /**
109     * Run the Daemon
110     */
111     public function run(){
112         echo "Running \n";
113         for($i=0; $i<10000; $i++){
114             $jobID = rand(0,10000000000000);
115             $launched = $this->launchJob($jobID);
116         }
117       
118         //Wait for child processes to finish before exiting here
119         while(count($this->currentJobs)){
120             echo "Waiting for current jobs to finish... \n";
121             sleep(1);
122         }
123     }
124   
125     /**
126     * Launch a job from the job queue
127     */
128     protected function launchJob($jobID){
129         $pid = pcntl_fork();
130         if($pid == -1){
131             //Problem launching the job
132             error_log('Could not launch new job, exiting');
133             return false;
134         }
135         else if ($pid){
136             // Parent process
137             // Sometimes you can receive a signal to the childSignalHandler function before this code executes if
138             // the child script executes quickly enough!
139             //
140             $this->currentJobs[$pid] = $jobID;
141           
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]);
148             }
149         }
150         else{
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";
154             exit($exitStatus);
155         }
156         return true;
157     }
158   
159     public function childSignalHandler($signo, $pid=null, $status=null){
160       
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
163         if(!$pid){
164             $pid = pcntl_waitpid(-1, $status, WNOHANG);
165         }
166       
167         //Make sure we get all of the exited children
168         while($pid > 0){
169             if($pid && isset($this->currentJobs[$pid])){
170                 $exitCode = pcntl_wexitstatus($status);
171                 if($exitCode != 0){
172                     echo "$pid exited with status ".$exitCode."\n";
173                 }
174                 unset($this->currentJobs[$pid]);
175             }
176             else if($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;
181             }
182             $pid = pcntl_waitpid(-1, $status, WNOHANG);
183         }
184         return true;
185     }
186 }
187
188
189
190 */
191
192
193
194 function notifier(&$a,$item_id,$parent_id) {
195
196         $pid = pcntl_fork();
197             
198         if ($pid == (-1)) {
199                 notice("Failed to launch background notifier." . EOL );
200                 return;
201         }       
202
203         if ($pid > 0) {
204                 // parent process - regenerate our connections in case the kid kills them
205         
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();
210                 session_start();
211
212                 // go back and finish the page
213                 return;
214         } 
215         else {
216                 // We are the child
217
218         // fetch item
219
220         // if not parent, fetch it
221
222         // atomify
223
224         // expand list of recipients
225
226         // grab the contact records
227
228         // foreach recipient
229
230         // if no dfrn-id continue
231
232         // fetch_url dfrn-notify
233
234         // decrypt challenge
235
236         // post result
237
238         // continue
239
240                 killme();
241         }
242 }