class Swee::Server
Attributes
code_reload[R]
Public Class Methods
new()
click to toggle source
# File lib/swee/server.rb, line 7 def initialize @config = Swee.config @options = @config.server @signature = nil @handle_request_mode = @options[:handle_request_mode] @restart_mode = @options[:restart_mode] @pid_file = File.expand_path(@options[:pid_file],ENV["app_path"]) @touch_file = File.expand_path(@options[:touch_file],ENV["app_path"]) @logger = nil @log_file_options = @options[:log_file] @log_file = File.expand_path(@log_file_options.first,ENV["app_path"]) @log_file_options[0] = @log_file @logger_level = @options[:logger_level] @code_reload = @options[:code_reload] # 最大连接数 和 稳定连接处 @maximum_connections = @options[:max_connections] @maximum_persistent_connections = @options[:max_connections] # 监听端口 @listen = @options[:listen] # 实际连接 __id__ => connection @connections = {} # 超时时间 @timeout = 30 # 活动连接数 @persistent_connection_count = 0 # touch 模式重启时间 @restart_time = nil # 信号队列 暂时只处理 :USR2 @signal_queue = [] # 守护进程 @daemonize = @options[:run_background] # todo: 性能监控 # @performance_monitoring = @options[:performance_monitoring] end
Public Instance Methods
connection()
click to toggle source
连接
# File lib/swee/server.rb, line 273 def connection EventMachine::start_server "0.0.0.0", @listen, Connection do |_connection| _connection.server = self # 记录活动连接数 if @persistent_connection_count < @maximum_persistent_connections @persistent_connection_count += 1 end @connections[_connection.__id__] = _connection end end
connection_finished(connection)
click to toggle source
完成连接
# File lib/swee/server.rb, line 291 def connection_finished(connection) @persistent_connection_count -= 1 @connections.delete(connection.__id__) # TODO: 停止或重启 end
create_touch_and_pid_file()
click to toggle source
创建日志 和 pid 文件
# File lib/swee/server.rb, line 233 def create_touch_and_pid_file [@pid_file,@touch_file].each do |_file| if !File.exist?(_file) FileUtils.mkdir_p File.dirname(_file) open(_file,"w") File.chmod(0644, _file) end end end
current_pid?(pid)
click to toggle source
判断 pid 文件是否为 当前进程ID
# File lib/swee/server.rb, line 153 def current_pid? pid read_pid_file == Process.pid.to_s end
disconnect()
click to toggle source
断开
# File lib/swee/server.rb, line 286 def disconnect EventMachine.stop_server(@signature) end
handle_daemonize()
click to toggle source
处理守护进程(后台运行) 创建子进程 进程命名 注册守护进程重启
# File lib/swee/server.rb, line 204 def handle_daemonize # 先删除pid文件 remove_pid_file # todo 关闭io 管道 # rd, wr = IO.pipe # grandparent = $$ # 创建子进程 safefork && exit # 设定进程名称 $0 = "swee" # 重新创建pid文件 write_pid_file # 注册守护进程重启 at_exit{ # 简单的用异常判断 系统退出,并非其他异常 获得重启 if $!.class == SystemExit @logger << "Swee服务器重启!" remove_pid_file ::Swee::Engine.restart_server! end } end
handle_logger()
click to toggle source
处理日志 stdout 和 file 两种
# File lib/swee/server.rb, line 101 def handle_logger # 创建日志文件 if !File.exist?(@log_file) FileUtils.mkdir_p File.dirname(@log_file) end logs = [] logs << Logger.new(*@log_file_options) unless @daemonize logs << Logger.new(STDOUT) end # todo: 日志等级, datetime, 格式配置 # logs.each do |_logger| # _logger.level = @logger_level # _logger.datetime_format = '%Y-%m-%d %H:%M:%S' # _logger.formatter = proc do |severity, datetime, progname, msg| # "Started GET #{msg} at #{datetime}" # end # end @logger = SweeLogger.new logs.each { |_logger| @logger.addlog _logger } end
handle_pid_restart()
click to toggle source
处理pid重启方式
# File lib/swee/server.rb, line 138 def handle_pid_restart write_pid_file end
handle_restart()
click to toggle source
处理重启
# File lib/swee/server.rb, line 128 def handle_restart send "handle_" + @restart_mode.to_s + "_restart" end
handle_touch_restart()
click to toggle source
处理touch重启方式
# File lib/swee/server.rb, line 133 def handle_touch_restart @restart_time = File.mtime(@touch_file) end
logger()
click to toggle source
获取 Logger
STDOUT 和 File
# File lib/swee/server.rb, line 58 def logger @logger end
pid_mode?()
click to toggle source
判断是否为 USR2 pid 重启方式
# File lib/swee/server.rb, line 148 def pid_mode? @restart_mode == :pid end
read_pid_file()
click to toggle source
读取pid文件 用于 USR2 信号获得后和Process.pid 比对
# File lib/swee/server.rb, line 68 def read_pid_file File.read(@pid_file) end
remove_pid_file()
click to toggle source
删除pid文件 用于重启 和 exit
# File lib/swee/server.rb, line 63 def remove_pid_file File.delete(@pid_file) if @pid_file && File.exists?(@pid_file) end
restart()
click to toggle source
放入 注册的 exit_at 函数中 重启 停止服务 -> 删除pid文件 -> 退出进程
# File lib/swee/server.rb, line 94 def restart stop! remove_pid_file exit end
run!()
click to toggle source
启动服务器
# File lib/swee/server.rb, line 244 def run! # 创建日志和pid文件 create_touch_and_pid_file # 处理日志 handle_logger # 处理重启 handle_restart # EM默认配置 EventMachine.threadpool_size = 20 EventMachine.epoll EventMachine.set_descriptor_table_size(@maximum_connections) @logger << "正在启动swee服务器" EventMachine::run { @signature = connection @running = true # EM启动后处理后台守护进程运行 handle_daemonize if @daemonize # 追踪重启文件 trace_restart puts "swee 服务器已启动, 端口:#{@listen}" } end
running?()
click to toggle source
是否运行标志
# File lib/swee/server.rb, line 79 def running? @running end
stop!()
click to toggle source
强制停止
# File lib/swee/server.rb, line 84 def stop! @running = false disconnect EventMachine.stop @connections.each_value { |connection| connection.close_connection } end
touch_mode?()
click to toggle source
判断是否为 touch 重启方式
# File lib/swee/server.rb, line 143 def touch_mode? @restart_mode == :touch end
trace_restart()
click to toggle source
追踪重启 EM Timer 方式 每秒执行一次 touch: 每秒读取touch文件 mtime pid: trap usr2 信号放入 信号队列, 然后每秒追踪队列变化获取信号
# File lib/swee/server.rb, line 161 def trace_restart if touch_mode? EM.add_periodic_timer(1) { mtime = File.mtime(@touch_file) if mtime != @restart_time @restart_time = mtime puts "重启了" restart # 放弃 next_tick 原因:会在下次有请求时处理重启 # EM.next_tick { restart } end } end if pid_mode? EM.add_periodic_timer(1) { signal = @signal_queue.shift case signal when nil when :QUIT # graceful shutdown when :TERM, :INT # immediate shutdown stop! when :USR1 # rotate logs when :USR2 # exec binary, stay alive in case something went wrong _restart = current_pid? when :WINCH when :TTIN when :TTOU when :HUP end restart if _restart } trap(:USR2) { # 收到 USR2信号加入 信号队列 @signal_queue << :USR2 } end end
write_pid_file()
click to toggle source
写入Process.pid到 pid 文件
# File lib/swee/server.rb, line 73 def write_pid_file open(@pid_file,"w") { |f| f.write(Process.pid) } File.chmod(0644, @pid_file) end