PHP single-sample program running
I. Scenario Description:
Recently, a piece of business needs to constantly monitor changes in a directory. If there are files in the directory, start the PHP script to process them. The initial solution was to use crontab to execute the sh script, which is roughly as follows:
SOK=`ps -ef |grep /www/sender.sh | grep -v grep|wc -l`if [[ $SOK < 2 ]];then for f in `ls /www/queue`; do php /www/logsender.php /www/queue/$f done
An exception occurred during actual operation: ps-ef | grep xxx may not be able to correctly judge whether the process is being executed. if conditions will never be true, so that PHP scripts will never be executed. After consideration, we decided to create a class that is independent of other modules and can implement process Singleton operation to solve this problem.
Ii. solution design
1. Process Singleton through PID File
2. The PID file is automatically created and deleted when the program starts and exits, so that you do not need to delete the PID file in the Business Code.
3. Try to ensure code independence without affecting business code
Iii. Principles
1. Start creating a PID File
2. semaphores such as program exit and killing are used to delete PID files.
3. Add destructor. when an object is destroyed, delete the PID file.
Iv. Problems Encountered
When the program Exits normally, it cannot capture the semaphores. I don't know if the semaphores are selected incorrectly. ctrl + c and other signals are normal. If this can solve the semaphores when the capture program Exits normally, it can replace the Destructor scheme, which is more stable.
V. Code
Single (); **/class DaemonSingle {// PID file path private $ pid_dir; // PID file name private $ filename; // PID file full path name private $ pid_file; /*** constructor * @ param $ filename * @ param string $ pid_dir */public function _ construct ($ filename, $ pid_dir = '/tmp /') {if (empty ($ filename) throw new JetException ('filename cannot be empty... '); $ this-> filename = $ filename; $ this-> pid_dir = $ pid_dir; $ this-> pid_file = $ this-> pi D_dir. DIRECTORY_SEPARATOR. substr (basename ($ this-> filename), 0,-4 ). '. pid ';}/*** single instance mode startup interface * @ throws JetException */public function single () {$ this-> check_pcntl (); if (file_exists ($ this-> pid_file) {throw new Exception ('the process is already running... ') ;}$ this-> create_pid_file ();}/*** @ throws JetException */private function create_pid_file () {if (! Is_dir ($ this-> pid_dir) {mkdir ($ this-> pid_dir);} $ fp = fopen ($ this-> pid_file, 'w'); if (! $ Fp) {throw new Exception ('cannot create pid file... ');} fwrite ($ fp, posix_getpid (); fclose ($ fp); $ this-> pid_create = true ;} /*** Environment check * @ throws Exception */public function check_pcntl () {// Make sure PHP has support for pcntl if (! Function_exists ('pcntl _ signal ') {$ message = 'php does not appear to be compiled with the pcntl extension. this is neccesary for daemonization '; throw new Exception ($ message);} // Signal Processing pcntl_signal (SIGTERM, array (& $ this, signal_handler); pcntl_signal (SIGINT, array (& $ this, signal_handler); pcntl_signal (SIGQUIT, array (& $ this, signal_handler )); // Enable PHP 5.3 garbage collection if (function_exists ('gc _ enabled') {gc_enable (); $ this-> gc_enabled = gc_enabled ();}} /*** signal processing function. When the program exits abnormally, safely delete the PID file * @ param $ signal */public function signal_handler ($ signal) {switch ($ signal) {case SIGINT: case SIGQUIT: case SIGTERM: {self: safe_quit (); break ;}}/ *** exit safely and delete the PID file */public function safe_quit () {if (file_exists ($ this-> pid_file) {$ pid = intval (posix_getpid (); $ file_pid = intval (file_get_contents ($ this-> pid_file )); if ($ pid = $ file_pid) {unlink ($ this-> pid_file) ;}} posix_kill (0, SIGKILL); exit (0 );} /*** destructor: Delete the PID file */public function _ destruct () {$ this-> safe_quit ();}}