serverengine 2.0.0pre1-x64-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +20 -0
  5. data/Changelog +122 -0
  6. data/Gemfile +2 -0
  7. data/LICENSE +202 -0
  8. data/NOTICE +3 -0
  9. data/README.md +514 -0
  10. data/Rakefile +26 -0
  11. data/appveyor.yml +24 -0
  12. data/examples/server.rb +138 -0
  13. data/examples/spawn_worker_script.rb +38 -0
  14. data/lib/serverengine.rb +46 -0
  15. data/lib/serverengine/blocking_flag.rb +77 -0
  16. data/lib/serverengine/command_sender.rb +89 -0
  17. data/lib/serverengine/config_loader.rb +82 -0
  18. data/lib/serverengine/daemon.rb +233 -0
  19. data/lib/serverengine/daemon_logger.rb +135 -0
  20. data/lib/serverengine/embedded_server.rb +67 -0
  21. data/lib/serverengine/multi_process_server.rb +155 -0
  22. data/lib/serverengine/multi_spawn_server.rb +95 -0
  23. data/lib/serverengine/multi_thread_server.rb +80 -0
  24. data/lib/serverengine/multi_worker_server.rb +150 -0
  25. data/lib/serverengine/privilege.rb +57 -0
  26. data/lib/serverengine/process_manager.rb +508 -0
  27. data/lib/serverengine/server.rb +178 -0
  28. data/lib/serverengine/signal_thread.rb +116 -0
  29. data/lib/serverengine/signals.rb +31 -0
  30. data/lib/serverengine/socket_manager.rb +171 -0
  31. data/lib/serverengine/socket_manager_unix.rb +98 -0
  32. data/lib/serverengine/socket_manager_win.rb +154 -0
  33. data/lib/serverengine/supervisor.rb +313 -0
  34. data/lib/serverengine/utils.rb +62 -0
  35. data/lib/serverengine/version.rb +3 -0
  36. data/lib/serverengine/winsock.rb +128 -0
  37. data/lib/serverengine/worker.rb +81 -0
  38. data/serverengine.gemspec +37 -0
  39. data/spec/blocking_flag_spec.rb +59 -0
  40. data/spec/daemon_logger_spec.rb +175 -0
  41. data/spec/daemon_spec.rb +169 -0
  42. data/spec/multi_process_server_spec.rb +113 -0
  43. data/spec/server_worker_context.rb +232 -0
  44. data/spec/signal_thread_spec.rb +94 -0
  45. data/spec/socket_manager_spec.rb +119 -0
  46. data/spec/spec_helper.rb +19 -0
  47. data/spec/supervisor_spec.rb +215 -0
  48. metadata +184 -0
@@ -0,0 +1,82 @@
1
+ #
2
+ # ServerEngine
3
+ #
4
+ # Copyright (C) 2012-2013 Sadayuki Furuhashi
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ require 'serverengine/daemon_logger'
19
+
20
+ module ServerEngine
21
+
22
+ module ConfigLoader
23
+ def initialize(load_config_proc={}, &block)
24
+ if block
25
+ @load_config_proc = block
26
+ else
27
+ if load_config_proc.is_a?(Hash)
28
+ @load_config_proc = lambda { load_config_proc }
29
+ else
30
+ @load_config_proc = load_config_proc
31
+ end
32
+ end
33
+
34
+ @logger = nil
35
+
36
+ reload_config
37
+ end
38
+
39
+ attr_reader :config
40
+ attr_accessor :logger
41
+
42
+ def reload_config
43
+ @config = @load_config_proc.call
44
+
45
+ @logger_class = @config[:logger_class] || DaemonLogger
46
+
47
+ if @logger
48
+ logdev = logdev_from_config(@config)
49
+ unless logdev.is_a?(IO)
50
+ # Here doesn't allow to change logdev to IO dynamically
51
+ # because Server#start_io_logging_thread can't follow it.
52
+ @logger.logdev = logdev
53
+ end
54
+ @logger.level = @config[:log_level] || 'debug'
55
+ end
56
+
57
+ nil
58
+ end
59
+
60
+ private
61
+
62
+ def create_logger
63
+ if logger = @config[:logger]
64
+ @logger = logger
65
+ else
66
+ @logger = @logger_class.new(logdev_from_config(@config), @config)
67
+ end
68
+ end
69
+
70
+ def logdev_from_config(config)
71
+ case c = @config[:log]
72
+ when nil # default
73
+ return STDERR
74
+ when "-"
75
+ return STDOUT
76
+ else
77
+ return c
78
+ end
79
+ end
80
+ end
81
+
82
+ end
@@ -0,0 +1,233 @@
1
+ #
2
+ # ServerEngine
3
+ #
4
+ # Copyright (C) 2012-2013 FURUHASHI Sadayuki
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ require 'serverengine/command_sender'
19
+ require 'serverengine/config_loader'
20
+ require 'serverengine/privilege'
21
+ require 'serverengine/supervisor'
22
+
23
+ module ServerEngine
24
+
25
+ class Daemon
26
+ include ConfigLoader
27
+
28
+ def initialize(server_module, worker_module, load_config_proc={}, &block)
29
+ @server_module = server_module
30
+ @worker_module = worker_module
31
+
32
+ super(load_config_proc, &block)
33
+
34
+ @daemonize = @config.fetch(:daemonize, false)
35
+
36
+ if @config.fetch(:supervisor, false)
37
+ @create_server_proc = lambda do |_load_config_proc,logger|
38
+ s = Supervisor.new(server_module, worker_module, _load_config_proc)
39
+ s.logger = logger
40
+ s
41
+ end
42
+ else
43
+ @create_server_proc = Supervisor.create_server_proc(server_module, worker_module, @config)
44
+ end
45
+
46
+ @daemon_process_name = @config[:daemon_process_name]
47
+ @daemonize_error_exit_code = @config[:daemonize_error_exit_code] || 1
48
+
49
+ @pid_path = @config[:pid_path]
50
+ @chuser = @config[:chuser]
51
+ @chgroup = @config[:chgroup]
52
+ @chumask = @config[:chumask]
53
+
54
+ @pid = nil
55
+ @command_pipe = @config.fetch(:command_pipe, nil)
56
+ @command_sender = @config.fetch(:command_sender, ServerEngine.windows? ? "pipe" : "signal")
57
+ if @command_sender == "pipe"
58
+ extend ServerEngine::CommandSender::Pipe
59
+ else
60
+ extend ServerEngine::CommandSender::Signal
61
+ end
62
+ end
63
+
64
+ # server is available when run() is called. It is a Supervisor instance if supervisor is set to true. Otherwise a Server instance.
65
+ attr_reader :server
66
+
67
+ def run
68
+ begin
69
+ exit main
70
+ rescue => e
71
+ ServerEngine.dump_uncaught_error(e)
72
+ exit @daemonize_error_exit_code
73
+ end
74
+ end
75
+
76
+ def self.run_server(server_module, worker_module, load_config_proc={}, &block)
77
+ Daemon.new(server_module, worker_module, load_config_proc, &block).server_main
78
+ end
79
+
80
+ def server_main
81
+ $0 = @daemon_process_name if @daemon_process_name
82
+
83
+ Privilege.change(@chuser, @chgroup)
84
+ File.umask(@chumask) if @chumask
85
+
86
+ s = create_server(create_logger)
87
+
88
+ STDIN.reopen(File::NULL)
89
+ STDOUT.reopen(File::NULL, "wb")
90
+ STDERR.reopen(File::NULL, "wb")
91
+
92
+ s.install_signal_handlers
93
+
94
+ s.main
95
+ end
96
+
97
+ def main
98
+ if @daemonize
99
+ if @command_sender == "pipe"
100
+ inpipe, @command_sender_pipe = IO.pipe
101
+ @command_sender_pipe.sync = true
102
+ @command_sender_pipe.binmode
103
+ end
104
+
105
+ if ServerEngine.windows?
106
+ ret = daemonize_with_spawn(inpipe)
107
+ else
108
+ ret = daemonize_with_double_fork(inpipe)
109
+ end
110
+
111
+ if @command_sender == "pipe"
112
+ inpipe.close
113
+ end
114
+ return ret
115
+ else
116
+ @pid = Process.pid
117
+ s = create_server(create_logger)
118
+ s.install_signal_handlers
119
+ begin
120
+ s.main
121
+ rescue SystemExit => e
122
+ return e.status
123
+ end
124
+ return 0
125
+ end
126
+ end
127
+
128
+ def daemonize_with_spawn(inpipe)
129
+ windows_daemon_cmdline = config[:windows_daemon_cmdline]
130
+ config = {}
131
+ if @command_sender == "pipe"
132
+ config[:in] = inpipe
133
+ end
134
+ @pid = Process.spawn(*Array(windows_daemon_cmdline), config)
135
+
136
+ write_pid_file
137
+ end
138
+
139
+ def daemonize_with_double_fork(inpipe)
140
+ rpipe, wpipe = IO.pipe
141
+ wpipe.sync = true
142
+
143
+ Process.fork do
144
+ begin
145
+ rpipe.close
146
+ if @command_sender == "pipe"
147
+ @command_sender_pipe.close
148
+ end
149
+
150
+ Process.setsid
151
+ Process.fork do
152
+ $0 = @daemon_process_name if @daemon_process_name
153
+ wpipe.write "#{Process.pid}\n"
154
+
155
+ Privilege.change(@chuser, @chgroup)
156
+ File.umask(@chumask) if @chumask
157
+
158
+ s = create_server(create_logger)
159
+ if @command_sender == "pipe"
160
+ s.instance_variable_set(:@command_pipe, inpipe)
161
+ end
162
+
163
+ STDIN.reopen(File::NULL)
164
+ STDOUT.reopen(File::NULL, "wb")
165
+ STDERR.reopen(File::NULL, "wb")
166
+
167
+ s.install_signal_handlers
168
+
169
+ wpipe.write "\n"
170
+ wpipe.close
171
+
172
+ begin
173
+ s.main
174
+ rescue SystemExit => e
175
+ exit e.status
176
+ end
177
+ end
178
+
179
+ exit 0
180
+ ensure
181
+ exit! @daemonize_error_exit_code
182
+ end
183
+ end
184
+
185
+ wpipe.close
186
+ @pid = rpipe.gets.to_i
187
+ data = rpipe.read
188
+ rpipe.close
189
+
190
+ if data != "\n"
191
+ return @daemonize_error_exit_code
192
+ end
193
+
194
+ write_pid_file
195
+
196
+ return 0
197
+ end
198
+
199
+ def write_pid_file
200
+ if @pid_path
201
+ File.open(@pid_path, "w") {|f|
202
+ f.write "#{@pid}\n"
203
+ }
204
+ end
205
+ end
206
+
207
+ def stop(graceful)
208
+ _stop(graceful)
209
+ end
210
+
211
+ def restart(graceful)
212
+ _restart(graceful)
213
+ end
214
+
215
+ def reload
216
+ _reload
217
+ end
218
+
219
+ def detach
220
+ _detach
221
+ end
222
+
223
+ def dump
224
+ _dump
225
+ end
226
+
227
+ private
228
+
229
+ def create_server(logger)
230
+ @server = @create_server_proc.call(@load_config_proc, logger)
231
+ end
232
+ end
233
+ end
@@ -0,0 +1,135 @@
1
+ #
2
+ # ServerEngine
3
+ #
4
+ # Copyright (C) 2012-2013 Sadayuki Furuhashi
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ require 'logger'
19
+
20
+ module ServerEngine
21
+
22
+ class ::Logger::LogDevice
23
+ def reopen!
24
+ if filename = @filename
25
+ @dev.reopen(filename, 'a')
26
+ @dev.sync = true
27
+ end
28
+ end
29
+ end
30
+
31
+ class DaemonLogger < Logger
32
+ def initialize(logdev, config={})
33
+ @rotate_age = config[:log_rotate_age] || 5
34
+ @rotate_size = config[:log_rotate_size] || 1048576
35
+ @file_dev = nil
36
+
37
+ super(nil)
38
+
39
+ self.level = config[:log_level] || 'debug'
40
+ self.logdev = logdev
41
+ end
42
+
43
+ def logdev=(logdev)
44
+ # overwrites Logger's @logdev variable
45
+ if logdev.respond_to?(:write) and logdev.respond_to?(:close)
46
+ # IO
47
+ @logdev = logdev
48
+ @logdev.sync = true if @logdev.respond_to?(:sync=)
49
+ if @file_dev
50
+ old_file_dev = @file_dev
51
+ @file_dev = nil
52
+ old_file_dev.close
53
+ end
54
+ elsif !@file_dev || @file_dev.filename != logdev
55
+ # update path string
56
+ old_file_dev = @file_dev
57
+ @file_dev = LogDevice.new(logdev, shift_age: @rotate_age, shift_size: @rotate_size)
58
+ old_file_dev.close if old_file_dev
59
+ @logdev = @file_dev
60
+ end
61
+ logdev
62
+ end
63
+
64
+ # override add method
65
+ def add(severity, message = nil, progname = nil, &block)
66
+ if severity < @level
67
+ return true
68
+ end
69
+ if message.nil?
70
+ if block_given?
71
+ message = yield
72
+ else
73
+ message = progname
74
+ progname = nil
75
+ end
76
+ end
77
+ progname ||= @progname
78
+ self << format_message(SEVERITY_FORMATS_[severity+1], Time.now, progname, message)
79
+ true
80
+ end
81
+
82
+ module Severity
83
+ include Logger::Severity
84
+ TRACE = -1
85
+ end
86
+ include Severity
87
+
88
+ SEVERITY_FORMATS_ = %w(TRACE DEBUG INFO WARN ERROR FATAL ANY)
89
+
90
+ def level=(expr)
91
+ case expr.to_s
92
+ when 'fatal', FATAL.to_s
93
+ e = FATAL
94
+ when 'error', ERROR.to_s
95
+ e = ERROR
96
+ when 'warn', WARN.to_s
97
+ e = WARN
98
+ when 'info', INFO.to_s
99
+ e = INFO
100
+ when 'debug', DEBUG.to_s
101
+ e = DEBUG
102
+ when 'trace', TRACE.to_s
103
+ e = TRACE
104
+ else
105
+ raise ArgumentError, "invalid log level: #{expr}"
106
+ end
107
+
108
+ super(e)
109
+ end
110
+
111
+ def trace?; @level <= TRACE; end
112
+
113
+ def reopen!
114
+ @file_dev.reopen! if @file_dev
115
+ nil
116
+ end
117
+
118
+ def reopen
119
+ begin
120
+ reopen!
121
+ return true
122
+ rescue
123
+ # TODO log?
124
+ return false
125
+ end
126
+ end
127
+
128
+ def close
129
+ @file_dev.close if @file_dev
130
+ nil
131
+ end
132
+
133
+ end
134
+
135
+ end