Skip to content
This repository has been archived by the owner on Jan 5, 2022. It is now read-only.

Commit

Permalink
Merge branch 'master' of github.com:shaneharter/PHP-Daemon
Browse files Browse the repository at this point in the history
  • Loading branch information
shaneharter committed Feb 9, 2011
2 parents f9187ca + b6e333a commit cd90bb4
Showing 1 changed file with 28 additions and 22 deletions.
50 changes: 28 additions & 22 deletions README
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
PHP-Daemon

Create solid, long-running PHP daemon processes by extending this Core_Daemon base class. It includes process management with forking and auto-restart features, signal handling, logging and alerts, and a locking mechanism to prevent multiple simultaneous instances.
Create solid, long-running PHP daemon processes by extending this Core_Daemon base class. Unlike other popular daemon libraries, PHP-Daemon has a built-in timer. By setting the loop interval and providing an execute method, the library runs the while loop for you and calls your execute() method at the desired frequency.

Crontab begins to work poorly when you have tasks that need to run every minute or two, and it has no support for running tasks every second or sub-second. Using PHP-Daemon you can run a task at any interval you require, whether that's every 10 seconds or 10 times per second.

I use this in production. It includes many features to make it durable and stable for my mission-critical uses.

Requires:
PHP 5.3 or Higher
Expand All @@ -10,13 +14,31 @@ Memcache Connection

Notable Features:

Loop Frequency
The internal run loop can run at whatever frequency you define. If you wish it to execute 5 times per second, or once every 5 seconds, all you have to do is set the ->loop_interval property. If do set it at '5', and your code takes 2 seconds to execute, it will sleep for the next 3 seconds, wake up, and iterate. If you set it at '5' and it's still running at 5 seconds, it will log it as an error condition.
* Built-In while() loop and micro-time timer.
Example: You set "->loop_interval=1". The PHP-Daemon will call your execute() method and time it. Suppose it takes 0.2 seconds. Upon its completion, the timer will sleep for the remaining 8/10 second. It wakes-up and then iterates. If your execute() method does not return before the end of the loop_interval (1 second in this case), an error will be logged. But since the execute() method is blocking, the next iteration will not begin until the first is complete.

* Braindead-Simple Forking for tasks that can be parallelized
Suppose your execute() method needed to push its results to an external API. If your interval is at 1 second you just don't have enough time to use an external resource. In these instances, PHP-Daemon provides a fork() method. It accepts a callback (todo: a Closure). When called, it spawns a child process, executes the callback, and exits. You have to be careful, dozens of long-running, possibly hung child processes is not good. But when used carefully it gives you a very simple, very powerful tool and you don't have to worry about mastering the idiosyncrasies of PHP forking.

* Auto Restart
No matter how diligent you are, memory bloat can occur. PHP-Daemon is able to auto-restart itself both as an attempt to recover from a fatal error, and on a user-defined interval to combat memory bloat. Only available when running in "Daemon mode" (-d at the command prompt), the built-in timer will track total runtime and when it hits the threshold you've set in the ini file, it will perform a graceful restart.

Signal Handling
The daemon listens for 3 signals: SIGINT, SIGHUP, SIGUSR1. When you send the Daemon a standard 'kill [pid]' SIGINT, it will do an ordered shutdown: It will finish the current iteration of the run loop and then shutdown. If you send a 'kill -1 [pid]' HUP command, it will restart the daemon. And if you send a 'kill -10 [pid]' USR1 signal, it will respond by dumping a block of debug variables to either the log or stdout or both, depending on how you configure logging.
* Signal Handling
By default PHP-Daemon listens for 3 signals: SIGINT, SIGHUP, SIGUSR1. When you send the Daemon a standard 'kill [pid]' SIGINT, it will do an graceful shutdown: It will finish the current iteration of the run loop and then shutdown. If you send a 'kill -1 [pid]' HUP command, it will trigger the auto-restart feature. And if you send a 'kill -10 [pid]' SIGUSR1, it will respond by dumping a block of runtime variables to either the log or stdout or both, depending on how you configure logging.

* Process Heartbeat
Every iteration, a "Heartbeat" is written to a special key in Memcache containing the PID of the process that wrote it. When a daemon starts, it checks that key for an existing heartbeat. If one is heard, it will instantly shut down to prevent multiple running instances of the same daemon. You can also use the heatbeat to monitor the daemon uptime.

* Memcache Wrapper
A small Memcache wrapper is included that implements easy namespacing but most importantly, auto_retry functionality. In our high-throughput memcache environment we occasionally have an issue where memcache was blocking at that specific microsecond and a key couldn't be written. To avoid this crashing the Daemon, auto-retry functionality was added. This feature will try several times to write the key -- until it reaches the timeout you specify.

* Simple Logging
By providing a filename, either staticly via the ->log_file property or dynamically by overloading the ->log_file() method, the system will keep a simple log file format, writing the timestamp, PID, and message. The PHP-Daemon system will log noteworthy events and you can easily add your own entries by calling either the ->log($message) method or, if appropriate, the ->fatal_error($message) method. An "alert" flag can be set that will email the $message to the distribution list you define in your constructor.

* Simple Config Loading
The daemon requires a config file with at least one key: config.auto_restart_interval. You can add any additional settings in there to control your daemon at runtime. All the settings are available by reading ->config[$section][$key].

Command Line Switches
* Command Line Switches
You can run a '-H' help command when you run the Daemon. It will dump a help menu that looks like this, but can be easily overridden for your daemon:

Example_Daemon
Expand All @@ -30,22 +52,6 @@ You can run a '-H' help command when you run the Daemon. It will dump a help men
-H Shows this help
-p PID_FILE File to write process ID out to

Auto Restart
When run in Daemon mode (-d at the command prompt), the system will keep an internal clock of it's runtime. When it reaches the point set in the config.auto_restart_interval key, it will automatically restart itself by calling itself using an exec() command and then killing the mature process in favor of the newly created. Additionally, when a fatal error is thrown, if it's been running for more than 10 seconds, it'll log the fatal but then attempt to recover by restarting itself.

Memcache Heartbeat
Every iteration, a "Heartbeat" is written to a special key in Memcache containing the PID of the process that wrote it. When a daemon starts, it checks that key for an existing heartbeat. If one is heard, it will gracefully shut down. You could also write external systems that poll that same key.

Memcache Wrapper
A small Memcache wrapper is included that implements auto_retry functionality. This adds more redundancy to Memcache to prevent a crash condition in the event where, at that specific microsecond, memcache was blocking and a key couldn't be written.

Simple Logging
By providing a filename, either staticly via the ->log_file property or dynamically by overloading the ->log_file() method, the system will keep a simple log file format, writing the timestamp, PID, and message. You can easily add entries to the log file throught your custom code by calling either the ->log($message) method or, if appropriate, the ->fatal_error($message) method.

Simple Config Loading
The daemon requires a config file with at least one key: config.auto_restart_interval. You can add any additional settings in there to control your daemon at runtime. All the settings are available by reading ->config[$section][$key].


TODO:

1. Replace this simple logging code (which grew more complex over time) with ZendLog or similar.
Expand Down

0 comments on commit cd90bb4

Please sign in to comment.