Browse Source

Merge pull request #221 from ares333/master

Add graceful stop and restart
walkor 8 years ago
parent
commit
06e2932f71
2 changed files with 71 additions and 6 deletions
  1. 13 0
      Connection/TcpConnection.php
  2. 58 6
      Worker.php

+ 13 - 0
Connection/TcpConnection.php

@@ -874,6 +874,19 @@ class TcpConnection extends ConnectionInterface
      */
     public function __destruct()
     {
+        static $mod;
         self::$statistics['connection_count']--;
+        if(Worker::getGracefulStop() && Worker::getStatus() === Worker::STATUS_SHUTDOWN){
+            if(!isset($mod)){
+                $mod=round((self::$statistics['connection_count']+1)/3);
+            }
+            if(0 === self::$statistics['connection_count']%$mod){
+                Worker::log('worker('.posix_getpid().') remains '.self::$statistics['connection_count'].' connection(s)'."\r");
+            }
+            if(0 === self::$statistics['connection_count']){
+                Worker::$globalEvent->destroy();
+                exit(0);
+            }
+        }
     }
 }

+ 58 - 6
Worker.php

@@ -419,6 +419,13 @@ class Worker
         'unix'  => 'unix',
         'ssl'   => 'tcp'
     );
+    
+    /**
+     * Graceful stop or not.
+     *
+     * @var string
+     */
+    protected static $_gracefulStop = false;
 
     /**
      * Run all worker instances.
@@ -716,9 +723,16 @@ class Worker
                 exit(0);
             case 'restart':
             case 'stop':
+                if($command2 === '-g'){
+                    self::$_gracefulStop = true;
+                    $sig = SIGTERM;
+                }else{
+                    self::$_gracefulStop = false;
+                    $sig = SIGINT;
+                }
                 self::log("Workerman[$start_file] is stoping ...");
                 // Send stop signal to master process.
-                $master_pid && posix_kill($master_pid, SIGINT);
+                $master_pid && posix_kill($master_pid, $sig);
                 // Timeout.
                 $timeout    = 5;
                 $start_time = time();
@@ -727,7 +741,7 @@ class Worker
                     $master_is_alive = $master_pid && posix_kill($master_pid, 0);
                     if ($master_is_alive) {
                         // Timeout?
-                        if (time() - $start_time >= $timeout) {
+                        if (!self::$_gracefulStop && time() - $start_time >= $timeout) {
                             self::log("Workerman[$start_file] stop fail");
                             exit;
                         }
@@ -821,6 +835,8 @@ class Worker
     {
         // stop
         pcntl_signal(SIGINT, array('\Workerman\Worker', 'signalHandler'), false);
+        // graceful stop
+        pcntl_signal(SIGTERM, array('\Workerman\Worker', 'signalHandler'), false);
         // reload
         pcntl_signal(SIGUSR1, array('\Workerman\Worker', 'signalHandler'), false);
         // status
@@ -840,12 +856,16 @@ class Worker
     {
         // uninstall stop signal handler
         pcntl_signal(SIGINT, SIG_IGN, false);
+        // uninstall graceful stop signal handler
+        pcntl_signal(SIGTERM, SIG_IGN, false);
         // uninstall reload signal handler
         pcntl_signal(SIGUSR1, SIG_IGN, false);
         // uninstall  status signal handler
         pcntl_signal(SIGUSR2, SIG_IGN, false);
         // reinstall stop signal handler
         self::$globalEvent->add(SIGINT, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler'));
+        // reinstall graceful stop signal handler
+        self::$globalEvent->add(SIGTERM, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler'));
         // reinstall  reload signal handler
         self::$globalEvent->add(SIGUSR1, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler'));
         // reinstall  status signal handler
@@ -864,8 +884,13 @@ class Worker
         switch ($signal) {
             // Stop.
             case SIGINT:
+                self::$_gracefulStop = false;
                 self::stopAll();
                 break;
+            // Graceful stop.
+            case SIGTERM:
+                self::$_gracefulStop = true;
+                self::stopAll();
             // Reload.
             case SIGUSR1:
                 self::$_pidsToRestart = self::getAllWorkerPids();
@@ -1318,9 +1343,16 @@ class Worker
             self::log("Workerman[" . basename(self::$_startFile) . "] Stopping ...");
             $worker_pid_array = self::getAllWorkerPids();
             // Send stop signal to all child processes.
+            if(self::$_gracefulStop){
+                $sig = SIGTERM;
+            }else{
+                $sig = SIGINT;
+            }
             foreach ($worker_pid_array as $worker_pid) {
-                posix_kill($worker_pid, SIGINT);
-                Timer::add(self::KILL_WORKER_TIMER_TIME, 'posix_kill', array($worker_pid, SIGKILL), false);
+                posix_kill($worker_pid, $sig);
+                if(!self::$_gracefulStop){
+                    Timer::add(self::KILL_WORKER_TIMER_TIME, 'posix_kill', array($worker_pid, SIGKILL), false);
+                }
             }
             // Remove statistics file.
             if (is_file(self::$_statisticsFile)) {
@@ -1332,10 +1364,30 @@ class Worker
             foreach (self::$_workers as $worker) {
                 $worker->stop();
             }
-            self::$globalEvent->destroy();
-            exit(0);
+            if(!self::$_gracefulStop) {
+                self::$globalEvent->destroy();
+                exit(0);
+            }
         }
     }
+    
+    /**
+     * Get process status.
+     *
+     * @return number
+     */
+    public static function getStatus(){
+        return self::$_status;
+    }
+    
+    /**
+     * If stop gracefully.
+     *
+     * @return number
+     */
+    public static function getGracefulStop(){
+        return self::$_gracefulStop;
+    }
 
     /**
      * Write statistics data to disk.