Page 1 of 1

PHP daemon questions

Posted: Thu Nov 06, 2003 1:48 am
by itbegary
I have this daemon that runs against a MySQL database every minute and does stuff. Some of the things that is does requires it to update a bunch of records in the database. Simple. So I wrote a daemon process so I can run it as a service.

Here is a segment of my code:

Code: Select all

function main(&$properties) {
                // <-- switch below for debugging.
	//$cpid = 0;
	$cpid = pcntl_fork();
	// Are we a child precoess?
	if ($cpid==0) &#123;
		// Yes we are...
		$i = 1;		
		init($properties);		
		mainloop($properties);
	&#125;
	else &#123;
		//We are not a child process.  We are the parent so 		//get out and die.  This allows the service to run properly...
	&#125; 
&#125;
Now mainloop() has a while (true) {} section that just runs and runs... In the course of the loop it might get a request to update the database. This process requires it to update some 50 to 100 records (some are dependent upon each other).

We would like to integrate some functionality to reload a configuration file. This simplest way, short of killing the service and restarting would be to use the signals, since that's what they are there for.

So I have been analyzing the code for doing the signals and wanted to get some feedback for implementing this. I think that it is straight forward but what I want to ensure this that if I do a HUP that it at leasts completes the batch of processing that it is working on prior to just dumping out.

So, what's the best approach for this. The reason for wanting to finish the batch is because most of the config changes are database changes (right now anyways) so if we HUP in the middle then it ends up getting the wrong DB information... (that's just one of a few cases).

Code segment from php manual:

Code: Select all

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

// signal handler function
function sig_handler($signo) &#123;

     switch($signo) &#123;
         case SIGTERM:
             // handle shutdown tasks
             exit;
             break;
         case SIGHUP:
             // handle restart tasks
             break;
         case SIGUSR1:
             print "Caught SIGUSR1...\n";
             break;
         default:
             // handle all other signals
     &#125;

&#125;

print "Installing signal handler...\n";

// setup signal handlers
pcntl_signal(SIGTERM, "sig_handler");
pcntl_signal(SIGHUP,  "sig_handler");
pcntl_signal(SIGUSR1, "sig_handler");

// or use an object, available as of PHP 4.3.0
// pcntl_signal(SIGUSR1, array($obj, "do_something");

print "Generating signal SIGTERM to self...\n";

// send SIGUSR1 to current process id
posix_kill(posix_getpid(), SIGUSR1);

print "Done\n"

?>
Does this make sense or is there is simpler way to do this.

BTW, the daemon is run as "nohup ./mydaemon.php &"

TIA,

Gary

Posted: Thu Nov 06, 2003 7:15 am
by BDKR
I'm waiting for a ride at this moment, but I plan on posting something. If I forget and don't get back to you sometime today, please remind me.

Cheers,
BDKR

Re: PHP daemon questions

Posted: Thu Nov 06, 2003 8:00 am
by BDKR
Well, as it turns out, my ride is going to be late, and so am I. Great!

Anyway.....

Before going on, I was thinking a while back on a way of implementing (mimmic) threads using forked procs and IPC. While I was thinking this, someone else did it.

Here are some of my thoughts on this over at my weblog.

http://mgaps.highsidecafe.com/index.php ... mit=search

I used shared memory to make sure that child procs were synchronized with one another.

That aside, I have a question.
Now mainloop() has a while (true) {} section that just runs and runs... In the course of the loop it might get a request to update the database. This process requires it to update some 50 to 100 records (some are dependent upon each other).
How does the process recieve this request? Are you using sockets?

A couple of thoughts.

1) If that's the case, couldn't child procs communicate with the parent with those same sockets?

2) What about the idea of creating a queue for holding incoming requests (however they may be recieved) and looking at those at the bottom of the loop. If one of those is a sighup, wait for the completion of tasks by child procs (how would you know? shared memory perhaps?) then restart.

If you are curious about some code for queues, I have some functions and an object that can be found at http://mgaps.highsidecafe.com/tools/ques.txt. This is rendered moot with the ADT extension, but short of having that and PHP5, it will do the trick.

Cheers,
BDKR

Re: PHP daemon questions

Posted: Thu Nov 06, 2003 8:25 am
by Weirdan
BDKR wrote: 1) If that's the case, couldn't child procs communicate with the parent with those same sockets?
Parent process dies just after it's forked. It's the common practice when writing a daemon.

Re: PHP daemon questions

Posted: Thu Nov 06, 2003 8:41 am
by BDKR
Weirdan wrote:
BDKR wrote: 1) If that's the case, couldn't child procs communicate with the parent with those same sockets?
Parent process dies just after it's forked. It's the common practice when writing a daemon.
That's not true. If it were, how does Apache work? I prototyped a load balancer in PHP using sockets, shared memory, and forking procs. The parent stays alive as it acts as a traffic cop listening for new connections.

Is there some document or something somewhere that states this?

BDKR

Posted: Thu Nov 06, 2003 9:14 am
by Weirdan
Parent dies to detach from pty.
Apache starts in two stages: firstly it forks to detach from pty (parent dies immediately), then forked process become a master, waits for connections, spawning children as necessary.

look at detach function defined in main/http_main.c module in source tree of Apache.

Posted: Thu Nov 06, 2003 10:55 am
by itbegary
To answer the first question we are not using sockets. We have a dozen processes from other systems that insert what I call "action data" into a shared mysql database. This daemon reads that database looking for things to do.

When the daemon finds something to do it executes a bunch of tasks. These tasks range from inserting a few records into a database, updating existing data in a database, sendmail out mail, or local shell execution. When completed the daemon marks the action as completed.

Part of this is for an invoicing system. Here is another case story. We insert a new invoice into the database. It is marked as unprocessed and it is also marked as to be emailed. The daemon picks up the record, does some creative work to it, does some CC processing, emails the invoice to a couple other places, does and XML dump to an archive file and finally marks the reacord as comlpete.

If I need to restart or stop the daemon I would want to make sure that daemon is between cycles. Clients really get mad when you bill there CC twice.

But reading the section on the pcntl functions it says that you need to put the declare into the block where it would apply.

Posted: Thu Nov 06, 2003 10:55 am
by BDKR
Weirdan wrote:Parent dies to detach from pty.
Apache starts in two stages: firstly it forks to detach from pty (parent dies immediately), then forked process become a master, waits for connections, spawning children as necessary.

look at detach function defined in main/http_main.c module in source tree of Apache.
Ahhh..., OK. That makes sense now. However, in the stuff I did in php before the app (or script) wouldn't detach from the pty unless I added a '&' (if I'm not mistaken) at the end of the command. What you're saying sounds more like a convention (that Apache follows) than an actual behaviour of some sort. In my load balancer app, as I said before, it didn't detach from the pty unless I told to by appending '&'. If I killed the pty or did the control-c routine or closed it from top, then the entire app and all children died along with it (if I remember correctly. It's been a while :?).

Thanx for the clarification on Apache though.

Cheers,
BDKR

Posted: Thu Nov 06, 2003 11:39 am
by Weirdan
BDKR wrote:What you're saying sounds more like a convention
I said 'usual practice', isn't it the same? I don't know English well enough to feel a difference...
BDKR wrote:In my load balancer app, as I said before, it didn't detach from the pty unless I told to by appending '&'. If I killed the pty or did the control-c routine or closed it from top, then the entire app and all children died along with it (if I remember correctly. It's been a while :?).
Yeah, you're completely right, if pty is closed all background jobs killed immediately. Exerpt from info bash:
If an attempt to exit Bash is while jobs are stopped, the shell prints a message warning that there are stopped jobs. The `jobs' command may then be used to inspect their status. If a second attempt to exit is made without an intervening command, Bash does not print another warning, and the stopped jobs are terminated.
I think it also applies to jobs running in background. Ctrl-C, however, do not interrupt background jobs.
BDKR wrote:Thanx for the clarification on Apache though.
You are welcome. It was as easy as:

Code: Select all

cd /usr/local/src/apache-1.3.28;
grep -r 'fork' * | less