[Groonga-commit] droonga/droonga-engine at e2bc408 [master] droonga-engine: support restarting without downtime

アーカイブの一覧に戻る

Kouhei Sutou null+****@clear*****
Mon Jan 5 19:04:32 JST 2015


Kouhei Sutou	2015-01-05 19:04:32 +0900 (Mon, 05 Jan 2015)

  New Revision: e2bc408526c0278b9a2ba9952384ae410c7725bb
  https://github.com/droonga/droonga-engine/commit/e2bc408526c0278b9a2ba9952384ae410c7725bb

  Message:
    droonga-engine: support restarting without downtime
    
    Note that droonga-engine itself can restart without downtime (it means
    that socket is alive while restarting) but Serf has downtime. Serf
    cluster will miss the droonga-engine node while restarting.
    
    TODO:
    
      * Re-consider how to operate restarting droonga-engine. The current
        implementation is `touch $BASE_DIR/restart.txt`. Is it reasonable
        way?

  Modified files:
    lib/droonga/command/droonga_engine.rb
    lib/droonga/path.rb

  Modified: lib/droonga/command/droonga_engine.rb (+121 -11)
===================================================================
--- lib/droonga/command/droonga_engine.rb    2015-01-05 17:45:53 +0900 (b7a0002)
+++ lib/droonga/command/droonga_engine.rb    2015-01-05 19:04:32 +0900 (1aa3134)
@@ -101,6 +101,10 @@ module Droonga
           @daemon          = nil
           @pid_file_path   = nil
           @ready_notify_fd = nil
+
+          @listen_fd       = nil
+          @heartbeat_fd    = nil
+          @serf_agent_pid  = nil
         end
 
         def engine_name
@@ -143,7 +147,28 @@ module Droonga
           daemon
         end
 
-        def to_command_line
+        def to_engine_command_line
+          command_line_options = [
+            "--host", host,
+            "--port", port.to_s,
+            "--tag", tag,
+            "--log-level", log_level,
+          ]
+          if log_file_path
+            command_line_options.concat(["--log-file", log_file_path.to_s])
+          end
+          if pid_file_path
+            command_line_options.concat(["--pid-file", pid_file_path.to_s])
+          end
+          if daemon?
+            command_line_options << "--daemon"
+          else
+            command_line_options << "--no-daemon"
+          end
+          command_line_options
+        end
+
+        def to_service_command_line
           command_line_options = [
             "--engine-name", engine_name,
           ]
@@ -156,14 +181,19 @@ module Droonga
           add_process_options(parser)
           add_path_options(parser)
           add_notification_options(parser)
+          add_internal_options(parser)
         end
 
         def listen_socket
-          @listen_socket ||= TCPServer.new(host, port)
+          @listen_socket ||= create_listen_socket
         end
 
         def heartbeat_socket
-          @heartbeat_socket ||= bind_heartbeat_socket
+          @heartbeat_socket ||= create_heartbeat_socket
+        end
+
+        def serf_agent_pid
+          @serf_agent_pid
         end
 
         private
@@ -297,10 +327,41 @@ module Droonga
           end
         end
 
-        def bind_heartbeat_socket
-          socket = UDPSocket.new(address_family)
-          socket.bind(host, port)
-          socket
+        def add_internal_options(parser)
+          parser.separator("")
+          parser.separator("Internal:")
+          parser.on("--listen-fd=FD", Integer,
+                    "FD of listen socket") do |fd|
+            @listen_fd = fd
+          end
+          parser.on("--heartbeat-fd=FD", Integer,
+                    "FD of heartbeat socket") do |fd|
+            @heartbeat_fd = fd
+          end
+          parser.on("--serf-agent-pid=PID", Integer,
+                    "PID of Serf agent") do |pid|
+            @serf_agent_pid = pid
+          end
+        end
+
+        def create_listen_socket
+          begin
+            TCPServer.new(host, port)
+          rescue Errno::EADDRINUSE
+            raise if @listen_fd.nil?
+            TCPServer.for_fd(@listen_fd)
+          end
+        end
+
+        def create_heartbeat_socket
+          begin
+            socket = UDPSocket.new(address_family)
+            socket.bind(host, port)
+            socket
+          rescue Errno::EADDRINUSE
+            raise if @heartbeat_fd.nil?
+            UDPSocket.for_fd(@heartbeat_fd)
+          end
         end
       end
 
@@ -311,6 +372,7 @@ module Droonga
           @configuration = configuration
           @loop = Coolio::Loop.default
           @log_file = nil
+          @pid_file_path = nil
         end
 
         def run
@@ -329,14 +391,15 @@ module Droonga
         end
 
         def write_pid_file
-          if****@confi*****_file_path
-            @configuration.pid_file_path.open("w") do |file|
+          @pid_file_path =****@confi*****_file_path
+          if @pid_file_path
+            @pid_file_path.open("w") do |file|
               file.puts(Process.pid)
             end
             begin
               yield
             ensure
-              FileUtils.rm_f(@configuration.pid_file_path.to_s)
+              FileUtils.rm_f(@pid_file_path.to_s)
             end
           else
             yield
@@ -347,6 +410,7 @@ module Droonga
           start_serf
           @service_runner = run_service
           setup_initial_on_ready
+          @restart_observer = run_restart_observer
           @catalog_observer = run_catalog_observer
           @command_runner = run_command_runner
 
@@ -392,6 +456,7 @@ module Droonga
         def stop_gracefully
           @command_runner.stop
           @catalog_observer.stop
+          @restart_observer.stop
           stop_serf
           @service_runner.stop_gracefully
         end
@@ -399,6 +464,7 @@ module Droonga
         def stop_immediately
           @command_runner.stop
           @catalog_observer.stop
+          @restart_observer.stop
           stop_serf
           @service_runner.stop_immediately
         end
@@ -424,6 +490,16 @@ module Droonga
           old_service_runner.stop_immediately
         end
 
+        def restart_self
+          old_pid_file_path = Pathname.new("#{@pid_file_path}.old")
+          FileUtils.mv(@pid_file_path.to_s, old_pid_file_path.to_s)
+          @pid_file_path = old_pid_file_path
+          stop_gracefully
+
+          engine_runner = EngineRunner.new(@configuration)
+          engine_runner.run
+        end
+
         def run_service
           service_runner = ServiceRunner.new(@loop, @configuration)
           service_runner.run
@@ -444,6 +520,15 @@ module Droonga
           @serf_agent.stop
         end
 
+        def run_restart_observer
+          restart_observer = FileObserver.new(@loop, Path.restart)
+          restart_observer.on_change = lambda do
+            restart_self
+          end
+          restart_observer.start
+          restart_observer
+        end
+
         def run_catalog_observer
           catalog_observer = FileObserver.new(@loop, Path.catalog)
           catalog_observer.on_change = lambda do
@@ -468,6 +553,31 @@ module Droonga
         end
       end
 
+      class EngineRunner
+        def initialize(configuration)
+          @configuration = configuration
+        end
+
+        def run
+          listen_fd =****@confi*****_socket.fileno
+          heartbeat_fd =****@confi*****_socket.fileno
+          env = {}
+          command_line = [
+            RbConfig.ruby,
+            "-S",
+            "droonga-engine",
+            "--listen-fd", listen_fd.to_s,
+            "--heartbeat-fd", heartbeat_fd.to_s,
+            *@configuration.to_engine_command_line,
+          ]
+          options = {
+            listen_fd => listen_fd,
+            heartbeat_fd => heartbeat_fd,
+          }
+          spawn(env, *command_line, options)
+        end
+      end
+
       class ServiceRunner
         def initialize(raw_loop, configuration)
           @raw_loop = raw_loop
@@ -499,7 +609,7 @@ module Droonga
             "--heartbeat-fd", heartbeat_fd.to_s,
             "--control-read-fd", control_write_in.fileno.to_s,
             "--control-write-fd", control_read_out.fileno.to_s,
-            *@configuration.to_command_line,
+            *@configuration.to_service_command_line,
           ]
           options = {
             listen_fd => listen_fd,

  Modified: lib/droonga/path.rb (+5 -0)
===================================================================
--- lib/droonga/path.rb    2015-01-05 17:45:53 +0900 (9251abc)
+++ lib/droonga/path.rb    2015-01-05 19:04:32 +0900 (a882878)
@@ -65,6 +65,11 @@ module Droonga
         Pathname.new(base_file_name).expand_path(base)
       end
 
+      # TODO: Re-consider this approach
+      def restart
+        base + "restart.txt"
+      end
+
       def buffer
         state + "buffer"
       end
-------------- next part --------------
HTML����������������������������...
ダウンロード 



More information about the Groonga-commit mailing list
アーカイブの一覧に戻る