Class: Swee::Server
Instance Attribute Summary collapse
-
#code_reload ⇒ Object
readonly
Returns the value of attribute code_reload.
Instance Method Summary collapse
-
#connection ⇒ Object
连接.
-
#connection_finished(connection) ⇒ Object
完成连接.
-
#create_touch_and_pid_file ⇒ Object
创建日志 和 pid 文件.
-
#current_pid?(pid) ⇒ Boolean
判断 pid 文件是否为 当前进程ID.
-
#disconnect ⇒ Object
断开.
-
#handle_daemonize ⇒ Object
处理守护进程(后台运行) 创建子进程 进程命名 注册守护进程重启.
-
#handle_logger ⇒ Object
处理日志 stdout 和 file 两种.
-
#handle_pid_restart ⇒ Object
处理pid重启方式.
-
#handle_restart ⇒ Object
处理重启.
-
#handle_touch_restart ⇒ Object
处理touch重启方式.
-
#initialize ⇒ Server
constructor
A new instance of Server.
-
#logger ⇒ Object
获取 Logger STDOUT 和 File.
-
#pid_mode? ⇒ Boolean
判断是否为 USR2 pid 重启方式.
-
#read_pid_file ⇒ Object
读取pid文件 用于 USR2 信号获得后和Process.pid 比对.
-
#remove_pid_file ⇒ Object
删除pid文件 用于重启 和 exit.
-
#restart ⇒ Object
放入 注册的 exit_at 函数中 重启 停止服务 -> 删除pid文件 -> 退出进程.
-
#run! ⇒ Object
启动服务器.
-
#running? ⇒ Boolean
是否运行标志.
-
#stop! ⇒ Object
强制停止.
-
#touch_mode? ⇒ Boolean
判断是否为 touch 重启方式.
-
#trace_restart ⇒ Object
追踪重启 EM Timer 方式 每秒执行一次 touch: 每秒读取touch文件 mtime pid: trap usr2 信号放入 信号队列, 然后每秒追踪队列变化获取信号.
-
#write_pid_file ⇒ Object
写入Process.pid到 pid 文件.
Methods included from Daemonize
Constructor Details
#initialize ⇒ Server
Returns a new instance of Server.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/swee/server.rb', line 8 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.(@options[:pid_file],ENV["app_path"]) @touch_file = File.(@options[:touch_file],ENV["app_path"]) @logger = nil @log_file_options = @options[:log_file] @log_file = File.(@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 |
Instance Attribute Details
#code_reload ⇒ Object (readonly)
Returns the value of attribute code_reload.
6 7 8 |
# File 'lib/swee/server.rb', line 6 def code_reload @code_reload end |
Instance Method Details
#connection ⇒ Object
连接
274 275 276 277 278 279 280 281 282 283 284 |
# File 'lib/swee/server.rb', line 274 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) ⇒ Object
完成连接
292 293 294 295 296 297 |
# File 'lib/swee/server.rb', line 292 def connection_finished(connection) @persistent_connection_count -= 1 @connections.delete(connection.__id__) # TODO: 停止或重启 end |
#create_touch_and_pid_file ⇒ Object
创建日志 和 pid 文件
234 235 236 237 238 239 240 241 242 |
# File 'lib/swee/server.rb', line 234 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) ⇒ Boolean
判断 pid 文件是否为 当前进程ID
154 155 156 |
# File 'lib/swee/server.rb', line 154 def current_pid? pid read_pid_file == Process.pid.to_s end |
#disconnect ⇒ Object
断开
287 288 289 |
# File 'lib/swee/server.rb', line 287 def disconnect EventMachine.stop_server(@signature) end |
#handle_daemonize ⇒ Object
处理守护进程(后台运行) 创建子进程 进程命名 注册守护进程重启
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
# File 'lib/swee/server.rb', line 205 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 ⇒ Object
处理日志 stdout 和 file 两种
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/swee/server.rb', line 102 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 ⇒ Object
处理pid重启方式
139 140 141 |
# File 'lib/swee/server.rb', line 139 def handle_pid_restart write_pid_file end |
#handle_restart ⇒ Object
处理重启
129 130 131 |
# File 'lib/swee/server.rb', line 129 def handle_restart send "handle_" + @restart_mode.to_s + "_restart" end |
#handle_touch_restart ⇒ Object
处理touch重启方式
134 135 136 |
# File 'lib/swee/server.rb', line 134 def handle_touch_restart @restart_time = File.mtime(@touch_file) end |
#logger ⇒ Object
获取 Logger STDOUT 和 File
59 60 61 |
# File 'lib/swee/server.rb', line 59 def logger @logger end |
#pid_mode? ⇒ Boolean
判断是否为 USR2 pid 重启方式
149 150 151 |
# File 'lib/swee/server.rb', line 149 def pid_mode? @restart_mode == :pid end |
#read_pid_file ⇒ Object
读取pid文件 用于 USR2 信号获得后和Process.pid 比对
69 70 71 |
# File 'lib/swee/server.rb', line 69 def read_pid_file File.read(@pid_file) end |
#remove_pid_file ⇒ Object
删除pid文件 用于重启 和 exit
64 65 66 |
# File 'lib/swee/server.rb', line 64 def remove_pid_file File.delete(@pid_file) if @pid_file && File.exists?(@pid_file) end |
#restart ⇒ Object
放入 注册的 exit_at 函数中 重启 停止服务 -> 删除pid文件 -> 退出进程
95 96 97 98 99 |
# File 'lib/swee/server.rb', line 95 def restart stop! remove_pid_file exit end |
#run! ⇒ Object
启动服务器
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 |
# File 'lib/swee/server.rb', line 245 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? ⇒ Boolean
是否运行标志
80 81 82 |
# File 'lib/swee/server.rb', line 80 def running? @running end |
#stop! ⇒ Object
强制停止
85 86 87 88 89 90 |
# File 'lib/swee/server.rb', line 85 def stop! @running = false disconnect EventMachine.stop @connections.each_value { |connection| connection.close_connection } end |
#touch_mode? ⇒ Boolean
判断是否为 touch 重启方式
144 145 146 |
# File 'lib/swee/server.rb', line 144 def touch_mode? @restart_mode == :touch end |
#trace_restart ⇒ Object
追踪重启 EM Timer 方式 每秒执行一次 touch: 每秒读取touch文件 mtime pid: trap usr2 信号放入 信号队列, 然后每秒追踪队列变化获取信号
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/swee/server.rb', line 162 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 ⇒ Object
写入Process.pid到 pid 文件
74 75 76 77 |
# File 'lib/swee/server.rb', line 74 def write_pid_file open(@pid_file,"w") { |f| f.write(Process.pid) } File.chmod(0644, @pid_file) end |