serverengine 2.0.0pre1-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
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
data/Rakefile ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rake/testtask'
5
+ require 'rake/clean'
6
+
7
+ require 'rspec/core/rake_task'
8
+
9
+ RSpec::Core::RakeTask.new(:spec)
10
+ task :default => [:spec, :build]
11
+
12
+ # 1. update Changelog and lib/serverengine/version.rb
13
+ # 2. bundle && bundle exec rake build:all
14
+ # 3. release 3 packages built on pkg/ directory
15
+ namespace :build do
16
+ desc 'Build gems for all platforms'
17
+ task :all do
18
+ Bundler.with_clean_env do
19
+ %w[ruby x86-mingw32 x64-mingw32].each do |name|
20
+ ENV['GEM_BUILD_FAKE_PLATFORM'] = name
21
+ Rake::Task["build"].execute
22
+ end
23
+ end
24
+ end
25
+ end
26
+
data/appveyor.yml ADDED
@@ -0,0 +1,24 @@
1
+ ---
2
+ install:
3
+ - SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
4
+ - ruby --version
5
+ - gem --version
6
+ - bundle install
7
+ build: off
8
+ test_script:
9
+ - bundle exec rake -rdevkit
10
+
11
+ environment:
12
+ matrix:
13
+ - ruby_version: "23-x64"
14
+ devkit: C:\Ruby23-x64\DevKit
15
+ - ruby_version: "23"
16
+ devkit: C:\Ruby23\DevKit
17
+ - ruby_version: "22-x64"
18
+ devkit: C:\Ruby23-x64\DevKit
19
+ - ruby_version: "22"
20
+ devkit: C:\Ruby23\DevKit
21
+ - ruby_version: "21-x64"
22
+ devkit: C:\Ruby23-x64\DevKit
23
+ - ruby_version: "21"
24
+ devkit: C:\Ruby23\DevKit
@@ -0,0 +1,138 @@
1
+ require 'serverengine'
2
+
3
+ require 'json'
4
+ require 'optparse'
5
+
6
+ # This is a script to run ServerEngine and SocketManager as a real process.
7
+ # bundle exec ruby example/server.rb [-t TYPE] [-w NUM]
8
+ # available type of workers are: embedded(default), process, thread, spawn
9
+
10
+ foreground = false
11
+ supervisor = false
12
+ worker_type = nil
13
+ workers = 4
14
+ exit_with_code = nil
15
+ exit_at_seconds = 5
16
+ exit_at_random = false
17
+ stop_immediately_at_exit = false
18
+ unrecoverable_exit_codes = []
19
+
20
+ opt = OptionParser.new
21
+ opt.on('-f'){ foreground = true }
22
+ opt.on('-x'){ supervisor = true }
23
+ opt.on('-t TYPE'){|v| worker_type = v }
24
+ opt.on('-w NUM'){|v| workers = v.to_i }
25
+ opt.on('-e NUM'){|v| exit_with_code = v.to_i }
26
+ opt.on('-s NUM'){|v| exit_at_seconds = v.to_i }
27
+ opt.on('-r'){ exit_at_random = true }
28
+ opt.on('-i'){ stop_immediately_at_exit = true }
29
+ opt.on('-u NUM'){|v| unrecoverable_exit_codes << v.to_i }
30
+ opt.parse!(ARGV)
31
+
32
+ if exit_with_code
33
+ ENV['EXIT_WITH_CODE'] = exit_with_code.to_s
34
+ ENV['EXIT_AT_SECONDS'] = exit_at_seconds.to_s
35
+ if exit_at_random
36
+ ENV['EXIT_AT_RANDOM'] = 'true'
37
+ end
38
+ end
39
+
40
+ module MyServer
41
+ attr_reader :socket_manager_path
42
+
43
+ def before_run
44
+ @socket_manager_path = ServerEngine::SocketManager::Server.generate_path
45
+ @socket_manager_server = ServerEngine::SocketManager::Server.open(@socket_manager_path)
46
+ rescue Exception => e
47
+ logger.error "unexpected error in server, class #{e.class}: #{e.message}"
48
+ raise
49
+ end
50
+
51
+ def after_run
52
+ logger.info "Server stopped."
53
+ @socket_manager_server.close
54
+ end
55
+ end
56
+
57
+ module MyWorker
58
+ def initialize
59
+ @stop = false
60
+ @socket_manager = ServerEngine::SocketManager::Client.new(server.socket_manager_path)
61
+ @exit_with_code = ENV.key?('EXIT_WITH_CODE') ? ENV['EXIT_WITH_CODE'].to_i : nil
62
+ @exit_at_seconds = ENV.key?('EXIT_AT_SECONDS') ? ENV['EXIT_AT_SECONDS'].to_i : nil
63
+ @exit_at_random = ENV.key?('EXIT_AT_RANDOM')
64
+ end
65
+
66
+ def main
67
+ # test to listen the same port
68
+ logger.info "Starting to run Worker."
69
+ _listen_sock = @socket_manager.listen_tcp('0.0.0.0', 12345)
70
+ stop_at = if @exit_with_code
71
+ stop_seconds = @exit_at_random ? rand(@exit_at_seconds) : @exit_at_seconds
72
+ logger.info "Stop #{stop_seconds} seconds later with code #{@exit_with_code}."
73
+ Time.now + stop_seconds
74
+ else
75
+ nil
76
+ end
77
+ until @stop
78
+ if stop_at && Time.now >= stop_at
79
+ logger.info "Exitting with code #{@exit_with_code}"
80
+ exit! @exit_with_code
81
+ end
82
+ logger.info "Awesome work!"
83
+ sleep 1
84
+ end
85
+ logger.info "Exitting"
86
+ rescue Exception => e
87
+ logger.warn "unexpected error, class #{e.class}: #{e.message}"
88
+ raise
89
+ end
90
+
91
+ def stop
92
+ @stop = true
93
+ end
94
+ end
95
+
96
+ module MySpawnWorker
97
+ def spawn(process_manager)
98
+ env = {
99
+ 'SERVER_ENGINE_CONFIG' => config.to_json,
100
+ 'SERVER_ENGINE_SOCKET_MANAGER_PATH' => server.socket_manager_path,
101
+ }
102
+ if ENV['EXIT_WITH_CODE']
103
+ env['EXIT_WITH_CODE'] = ENV['EXIT_WITH_CODE']
104
+ env['EXIT_AT_SECONDS'] = ENV['EXIT_AT_SECONDS']
105
+ if ENV['EXIT_AT_RANDOM']
106
+ env['EXIT_AT_RANDOM'] = 'true'
107
+ end
108
+ end
109
+ process_manager.spawn(env, "ruby", File.expand_path("../spawn_worker_script.rb", __FILE__))
110
+ rescue Exception => e
111
+ logger.error "unexpected error, class #{e.class}: #{e.message}"
112
+ raise
113
+ end
114
+ end
115
+
116
+ opts = {
117
+ daemonize: !foreground,
118
+ daemon_process_name: 'mydaemon',
119
+ supervisor: supervisor,
120
+ log: 'myserver.log',
121
+ pid_path: 'myserver.pid',
122
+ worker_type: worker_type,
123
+ workers: workers,
124
+ }
125
+ if stop_immediately_at_exit
126
+ opts[:stop_immediately_at_unrecoverable_exit] = true
127
+ end
128
+ unless unrecoverable_exit_codes.empty?
129
+ opts[:unrecoverable_exit_codes] = unrecoverable_exit_codes
130
+ end
131
+
132
+ worker_klass = MyWorker
133
+ if worker_type == 'spawn'
134
+ worker_klass = MySpawnWorker
135
+ end
136
+ se = ServerEngine.create(MyServer, worker_klass, opts)
137
+
138
+ se.run
@@ -0,0 +1,38 @@
1
+ $LOAD_PATH.unshift File.expand_path("../..", __FILE__)
2
+
3
+ require 'serverengine'
4
+ require 'json'
5
+
6
+ begin
7
+ conf = JSON.parse(ENV['SERVER_ENGINE_CONFIG'], symbolize_names: true)
8
+ logger = ServerEngine::DaemonLogger.new(conf[:log] || STDOUT, conf)
9
+ logger.info "Starting to run Worker."
10
+ socket_manager = ServerEngine::SocketManager::Client.new(ENV['SERVER_ENGINE_SOCKET_MANAGER_PATH'])
11
+ exit_with_code = ENV.key?('EXIT_WITH_CODE') ? ENV['EXIT_WITH_CODE'].to_i : nil
12
+ exit_at_seconds = ENV.key?('EXIT_AT_SECONDS') ? ENV['EXIT_AT_SECONDS'].to_i : nil
13
+ exit_at_random = ENV.key?('EXIT_AT_RANDOM')
14
+ stop_at = if exit_with_code
15
+ stop_seconds = exit_at_random ? rand(exit_at_seconds) : exit_at_seconds
16
+ logger.info "Stop #{stop_seconds} seconds later with code #{exit_with_code}."
17
+ Time.now + stop_seconds
18
+ else
19
+ nil
20
+ end
21
+
22
+ @stop = false
23
+ trap(:SIGTERM) { @stop = true }
24
+ trap(:SIGINT) { @stop = true }
25
+
26
+ _listen_sock = socket_manager.listen_tcp('0.0.0.0', 12345)
27
+ until @stop
28
+ if stop_at && Time.now >= stop_at
29
+ logger.info "Exitting with code #{exit_with_code}"
30
+ exit! exit_with_code
31
+ end
32
+ logger.info 'Awesome work!'
33
+ sleep 1
34
+ end
35
+ logger.info 'Exitting'
36
+ rescue Exception => e
37
+ logger.error "unexpected error in spawn worker, class #{e.class}: #{e.message}"
38
+ end
@@ -0,0 +1,46 @@
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
+ module ServerEngine
19
+
20
+ require 'sigdump'
21
+
22
+ require 'serverengine/version'
23
+
24
+ require 'serverengine/utils' # ServerEngine.windows? and other util methods
25
+
26
+ require 'serverengine/daemon'
27
+ require 'serverengine/supervisor'
28
+ require 'serverengine/server'
29
+ require 'serverengine/worker'
30
+ require 'serverengine/socket_manager'
31
+
32
+ def self.create(server_module, worker_module, load_config_proc={}, &block)
33
+ Daemon.new(server_module, worker_module, load_config_proc, &block)
34
+ end
35
+
36
+ def self.ruby_bin_path
37
+ if ServerEngine.windows?
38
+ require 'windows/library'
39
+ ruby_path = "\0" * 256
40
+ Windows::Library::GetModuleFileName.call(0, ruby_path, 256)
41
+ return ruby_path.rstrip.gsub(/\\/, '/')
42
+ else
43
+ return File.join(RbConfig::CONFIG["bindir"], RbConfig::CONFIG["RUBY_INSTALL_NAME"]) + RbConfig::CONFIG["EXEEXT"]
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,77 @@
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 'thread'
19
+
20
+ module ServerEngine
21
+ class BlockingFlag
22
+ def initialize
23
+ @set = false
24
+ @mutex = Mutex.new
25
+ @cond = ConditionVariable.new
26
+ end
27
+
28
+ def set!
29
+ toggled = false
30
+ @mutex.synchronize do
31
+ unless @set
32
+ @set = true
33
+ toggled = true
34
+ end
35
+ @cond.broadcast
36
+ end
37
+ return toggled
38
+ end
39
+
40
+ def reset!
41
+ toggled = false
42
+ @mutex.synchronize do
43
+ if @set
44
+ @set = false
45
+ toggled = true
46
+ end
47
+ @cond.broadcast
48
+ end
49
+ return toggled
50
+ end
51
+
52
+ def set?
53
+ @set
54
+ end
55
+
56
+ def wait_for_set(timeout=nil)
57
+ @mutex.synchronize do
58
+ unless @set
59
+ @cond.wait(@mutex, timeout)
60
+ end
61
+ return @set
62
+ end
63
+ end
64
+
65
+ alias_method :wait, :wait_for_set
66
+
67
+ def wait_for_reset(timeout=nil)
68
+ @mutex.synchronize do
69
+ if @set
70
+ @cond.wait(@mutex, timeout)
71
+ end
72
+ return !@set
73
+ end
74
+ end
75
+ end
76
+
77
+ end
@@ -0,0 +1,89 @@
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/signals'
19
+
20
+ module ServerEngine
21
+ module CommandSender
22
+ # requires send_signal method or @pid
23
+ module Signal
24
+ private
25
+ def _stop(graceful)
26
+ _send_signal(!ServerEngine.windows? && graceful ? Signals::GRACEFUL_STOP : Signals::IMMEDIATE_STOP)
27
+ end
28
+
29
+ def _restart(graceful)
30
+ _send_signal(graceful ? Signals::GRACEFUL_RESTART : Signals::IMMEDIATE_RESTART)
31
+ end
32
+
33
+ def _reload
34
+ _send_signal(Signals::RELOAD)
35
+ end
36
+
37
+ def _detach
38
+ _send_signal(Signals::DETACH)
39
+ end
40
+
41
+ def _dump
42
+ _send_signal(Signals::DUMP)
43
+ end
44
+
45
+ def _send_signal(sig)
46
+ if respond_to?(:send_signal, true)
47
+ send_signal(sig)
48
+ else
49
+ Process.kill(sig, @pid)
50
+ end
51
+ end
52
+ end
53
+
54
+ # requires @command_sender_pipe
55
+ module Pipe
56
+ private
57
+ def _stop(graceful)
58
+ begin
59
+ _send_command(graceful ? "GRACEFUL_STOP" : "IMMEDIATE_STOP")
60
+ rescue Errno::EPIPE
61
+ # already stopped, then nothing to do
62
+ ensure
63
+ @command_sender_pipe.close rescue nil
64
+ @command_sender_pipe = nil
65
+ end
66
+ end
67
+
68
+ def _restart(graceful)
69
+ _send_command(graceful ? "GRACEFUL_RESTART" : "IMMEDIATE_RESTART")
70
+ end
71
+
72
+ def _reload
73
+ _send_command("RELOAD")
74
+ end
75
+
76
+ def _detach
77
+ _send_command("DETACH")
78
+ end
79
+
80
+ def _dump
81
+ _send_command("DUMP")
82
+ end
83
+
84
+ def _send_command(cmd)
85
+ @command_sender_pipe.write cmd + "\n"
86
+ end
87
+ end
88
+ end
89
+ end