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����������������������������...ダウンロード