zeus 0.2.5 → 0.2.6
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.
- data/lib/zeus/server.rb +2 -0
- data/lib/zeus/server/acceptor.rb +45 -81
- data/lib/zeus/server/acceptor_error_state.rb +35 -0
- data/lib/zeus/server/acceptor_registration_monitor.rb +3 -1
- data/lib/zeus/server/forked_process.rb +71 -0
- data/lib/zeus/server/stage.rb +41 -58
- data/lib/zeus/version.rb +1 -1
- metadata +3 -1
data/lib/zeus/server.rb
CHANGED
@@ -8,7 +8,9 @@ module Zeus
|
|
8
8
|
autoload :Acceptor, 'zeus/server/acceptor'
|
9
9
|
autoload :FileMonitor, 'zeus/server/file_monitor'
|
10
10
|
autoload :ProcessTree, 'zeus/server/process_tree'
|
11
|
+
autoload :ForkedProcess, 'zeus/server/forked_process'
|
11
12
|
autoload :ClientHandler, 'zeus/server/client_handler'
|
13
|
+
autoload :AcceptorErrorState, 'zeus/server/acceptor_error_state'
|
12
14
|
autoload :ProcessTreeMonitor, 'zeus/server/process_tree_monitor'
|
13
15
|
autoload :AcceptorRegistrationMonitor, 'zeus/server/acceptor_registration_monitor'
|
14
16
|
|
data/lib/zeus/server/acceptor.rb
CHANGED
@@ -4,18 +4,45 @@ require 'socket'
|
|
4
4
|
# See Zeus::Server::ClientHandler for relevant documentation
|
5
5
|
module Zeus
|
6
6
|
class Server
|
7
|
-
class Acceptor
|
7
|
+
class Acceptor < ForkedProcess
|
8
|
+
attr_accessor :aliases, :description, :action
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
def descendent_acceptors
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def before_setup
|
15
|
+
register_with_client_handler(Process.pid)
|
16
|
+
end
|
17
|
+
|
18
|
+
def runloop!
|
19
|
+
loop do
|
20
|
+
prefork_action!
|
21
|
+
terminal, arguments = accept_connection # blocking
|
22
|
+
child = fork { __RUNNER__run(terminal, arguments) }
|
23
|
+
terminal.close
|
24
|
+
|
25
|
+
Process.detach(child)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def __RUNNER__run(terminal, arguments)
|
30
|
+
$0 = "zeus runner: #{@name}"
|
31
|
+
postfork_action!
|
32
|
+
@s_acceptor << $$ << "\n"
|
33
|
+
$stdin.reopen(terminal)
|
34
|
+
$stdout.reopen(terminal)
|
35
|
+
$stderr.reopen(terminal)
|
36
|
+
ARGV.replace(arguments)
|
37
|
+
|
38
|
+
@action.call
|
12
39
|
end
|
13
40
|
|
41
|
+
private
|
42
|
+
|
14
43
|
def register_with_client_handler(pid)
|
15
44
|
@s_client_handler, @s_acceptor = UNIXSocket.pair
|
16
|
-
|
17
45
|
@s_acceptor.puts registration_data(pid)
|
18
|
-
|
19
46
|
@server.__CHILD__register_acceptor(@s_client_handler)
|
20
47
|
end
|
21
48
|
|
@@ -23,91 +50,28 @@ module Zeus
|
|
23
50
|
{type: 'registration', pid: pid, commands: [name, *aliases], description: description}.to_json
|
24
51
|
end
|
25
52
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
53
|
+
def accept_connection
|
54
|
+
terminal = @s_acceptor.recv_io # blocking
|
55
|
+
arguments = JSON.parse(@s_acceptor.readline.chomp)
|
29
56
|
|
30
|
-
|
31
|
-
io.puts "#{error.backtrace[0]}: #{error.message} (#{error.class})"
|
32
|
-
error.backtrace[1..-1].each do |line|
|
33
|
-
io.puts "\tfrom #{line}"
|
34
|
-
end
|
57
|
+
[terminal, arguments]
|
35
58
|
end
|
36
59
|
|
37
|
-
def
|
38
|
-
|
39
|
-
Zeus.ui.as_zeus "starting error-state acceptor `#{@name}`"
|
40
|
-
|
41
|
-
Thread.new do
|
42
|
-
loop do
|
43
|
-
terminal = @s_acceptor.recv_io
|
44
|
-
_ = @s_acceptor.readline
|
45
|
-
@s_acceptor << 0 << "\n"
|
46
|
-
print_error(terminal, e)
|
47
|
-
terminal.close
|
48
|
-
end
|
49
|
-
end
|
60
|
+
def process_type
|
61
|
+
"acceptor"
|
50
62
|
end
|
51
63
|
|
52
|
-
def run
|
53
|
-
pid = fork {
|
54
|
-
$0 = "zeus acceptor: #{@name}"
|
55
|
-
pid = Process.pid
|
56
|
-
|
57
|
-
register_with_client_handler(pid)
|
58
|
-
|
59
|
-
@server.__CHILD__pid_has_ppid(pid, Process.ppid)
|
60
|
-
|
61
|
-
Zeus.ui.as_zeus "starting acceptor `#{@name}`"
|
62
|
-
trap("INT") {
|
63
|
-
Zeus.ui.as_zeus "killing acceptor `#{@name}`"
|
64
|
-
exit 0
|
65
|
-
}
|
66
|
-
|
67
|
-
# Apparently threads don't continue in forks.
|
68
|
-
Thread.new {
|
69
|
-
$LOADED_FEATURES.each do |f|
|
70
|
-
@server.__CHILD__pid_has_feature(pid, f)
|
71
|
-
end
|
72
|
-
}
|
73
|
-
|
74
|
-
loop do
|
75
|
-
prefork_action!
|
76
|
-
terminal = @s_acceptor.recv_io
|
77
|
-
arguments = JSON.parse(@s_acceptor.readline.chomp)
|
78
|
-
child = fork do
|
79
|
-
$0 = "zeus runner: #{@name}"
|
80
|
-
postfork_action!
|
81
|
-
@s_acceptor << $$ << "\n"
|
82
|
-
$stdin.reopen(terminal)
|
83
|
-
$stdout.reopen(terminal)
|
84
|
-
$stderr.reopen(terminal)
|
85
|
-
ARGV.replace(arguments)
|
86
|
-
|
87
|
-
@action.call
|
88
|
-
end
|
89
|
-
Process.detach(child)
|
90
|
-
terminal.close
|
91
|
-
end
|
92
|
-
|
93
|
-
}
|
94
|
-
currpid = Process.pid
|
95
|
-
at_exit {
|
96
|
-
if Process.pid == currpid
|
97
|
-
Process.kill(9, pid) rescue nil
|
98
|
-
end
|
99
|
-
}
|
100
|
-
pid
|
101
|
-
end
|
102
64
|
|
65
|
+
# these two methods should be part of the configuration DSL.
|
66
|
+
# They're here for now, but I want them out.
|
103
67
|
def prefork_action! # TODO : refactor
|
104
|
-
ActiveRecord::Base.clear_all_connections!
|
68
|
+
ActiveRecord::Base.clear_all_connections! rescue nil
|
105
69
|
end
|
106
70
|
|
107
71
|
def postfork_action! # TODO :refactor
|
108
|
-
ActiveRecord::Base.establish_connection
|
109
|
-
ActiveSupport::DescendantsTracker.clear
|
110
|
-
ActiveSupport::Dependencies.clear
|
72
|
+
ActiveRecord::Base.establish_connection rescue nil
|
73
|
+
ActiveSupport::DescendantsTracker.clear rescue nil
|
74
|
+
ActiveSupport::Dependencies.clear rescue nil
|
111
75
|
end
|
112
76
|
|
113
77
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
# See Zeus::Server::ClientHandler for relevant documentation
|
5
|
+
module Zeus
|
6
|
+
class Server
|
7
|
+
module ErrorStateAcceptor
|
8
|
+
attr_accessor :error
|
9
|
+
|
10
|
+
def print_error(io, error = @error)
|
11
|
+
io.puts "#{error.backtrace[0]}: #{error.message} (#{error.class})"
|
12
|
+
error.backtrace[1..-1].each do |line|
|
13
|
+
io.puts "\tfrom #{line}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
register_with_client_handler(Process.pid)
|
19
|
+
Zeus.ui.as_zeus "starting error-state acceptor `#{@name}`"
|
20
|
+
|
21
|
+
Thread.new do
|
22
|
+
loop do
|
23
|
+
terminal = @s_acceptor.recv_io
|
24
|
+
_ = @s_acceptor.readline
|
25
|
+
@s_acceptor << 0 << "\n"
|
26
|
+
print_error(terminal)
|
27
|
+
terminal.close
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
@@ -4,7 +4,9 @@ module Zeus
|
|
4
4
|
|
5
5
|
def datasource ; @sock ; end
|
6
6
|
def on_datasource_event ; handle_message ; end
|
7
|
-
|
7
|
+
# @__CHILD__sock is not closed here, as it's used by the master to respond
|
8
|
+
# for unbooted acceptors
|
9
|
+
def close_child_socket ; end
|
8
10
|
def close_parent_socket ; @sock.close ; end
|
9
11
|
|
10
12
|
def initialize
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Zeus
|
2
|
+
class Server
|
3
|
+
class ForkedProcess
|
4
|
+
HasNoChildren = Class.new(Exception)
|
5
|
+
|
6
|
+
attr_accessor :name
|
7
|
+
attr_reader :pid
|
8
|
+
def initialize(server)
|
9
|
+
@server = server
|
10
|
+
end
|
11
|
+
|
12
|
+
def notify_feature(feature)
|
13
|
+
@server.__CHILD__pid_has_feature(Process.pid, feature)
|
14
|
+
end
|
15
|
+
|
16
|
+
def descendent_acceptors
|
17
|
+
raise NotImplementedError
|
18
|
+
end
|
19
|
+
|
20
|
+
def process_type
|
21
|
+
raise "NotImplementedError"
|
22
|
+
end
|
23
|
+
|
24
|
+
def setup_forked_process(close_parent_sockets)
|
25
|
+
@server.__CHILD__close_parent_sockets if close_parent_sockets
|
26
|
+
@server.__CHILD__pid_has_ppid(Process.pid, Process.ppid)
|
27
|
+
|
28
|
+
$0 = "zeus #{process_type}: #{@name}"
|
29
|
+
|
30
|
+
Zeus.ui.as_zeus("starting #{process_type} `#{@name}`")
|
31
|
+
trap("INT") {
|
32
|
+
Zeus.ui.as_zeus("killing #{process_type} `#{@name}`")
|
33
|
+
exit 0
|
34
|
+
}
|
35
|
+
|
36
|
+
Thread.new {
|
37
|
+
$LOADED_FEATURES.each { |f| notify_feature(f) }
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def kill_pid_on_exit(pid)
|
42
|
+
currpid = Process.pid
|
43
|
+
at_exit { Process.kill(9, pid) if Process.pid == currpid rescue nil }
|
44
|
+
end
|
45
|
+
|
46
|
+
def runloop!
|
47
|
+
raise NotImplementedError
|
48
|
+
end
|
49
|
+
|
50
|
+
def before_setup
|
51
|
+
end
|
52
|
+
|
53
|
+
def after_setup
|
54
|
+
end
|
55
|
+
|
56
|
+
def run(close_parent_sockets = false)
|
57
|
+
@pid = fork {
|
58
|
+
before_setup
|
59
|
+
setup_forked_process(close_parent_sockets)
|
60
|
+
after_setup
|
61
|
+
runloop!
|
62
|
+
}
|
63
|
+
kill_pid_on_exit(@pid)
|
64
|
+
@pid
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
data/lib/zeus/server/stage.rb
CHANGED
@@ -2,40 +2,68 @@ module Zeus
|
|
2
2
|
class Server
|
3
3
|
# NONE of the code in the module is run in the master process,
|
4
4
|
# so every communication to the master must be done with IPC.
|
5
|
-
class Stage
|
6
|
-
|
5
|
+
class Stage < ForkedProcess
|
6
|
+
attr_accessor :stages, :actions
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
def initialize(server)
|
11
|
-
@server = server
|
8
|
+
def descendent_acceptors
|
9
|
+
@stages.map(&:descendent_acceptors).flatten
|
12
10
|
end
|
13
11
|
|
14
|
-
|
15
|
-
|
12
|
+
|
13
|
+
def after_setup
|
14
|
+
begin
|
15
|
+
@actions.each(&:call)
|
16
|
+
rescue => e
|
17
|
+
handle_load_error(e)
|
18
|
+
end
|
19
|
+
|
20
|
+
@pids = {}
|
21
|
+
@stages.each do |stage|
|
22
|
+
@pids[stage.run] = stage
|
23
|
+
end
|
16
24
|
end
|
17
25
|
|
18
|
-
def
|
19
|
-
|
26
|
+
def runloop!
|
27
|
+
loop do
|
28
|
+
begin
|
29
|
+
pid = Process.wait
|
30
|
+
rescue Errno::ECHILD
|
31
|
+
raise HasNoChildren.new("Stage `#{@name}` - All terminal nodes must be acceptors")
|
32
|
+
end
|
33
|
+
stage = @pids[pid]
|
34
|
+
@pids[stage.run] = stage
|
35
|
+
end
|
20
36
|
end
|
21
37
|
|
38
|
+
|
39
|
+
private
|
40
|
+
|
22
41
|
def register_acceptors_as_errors(e)
|
23
42
|
descendent_acceptors.each do |acc|
|
24
|
-
acc.
|
43
|
+
acc = acc.extend(AcceptorErrorState)
|
44
|
+
acc.error = e
|
45
|
+
acc.run
|
25
46
|
end
|
26
47
|
end
|
27
48
|
|
49
|
+
def process_type
|
50
|
+
"spawner"
|
51
|
+
end
|
28
52
|
|
29
|
-
def
|
53
|
+
def full_path_of_file_from_error(e)
|
30
54
|
errored_file = e.backtrace[0].scan(/(.+?):\d+:in/)[0][0]
|
31
55
|
|
32
56
|
# handle relative paths
|
33
57
|
unless errored_file =~ /^\//
|
34
58
|
errored_file = File.expand_path(errored_file, Dir.pwd)
|
35
59
|
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def handle_load_error(e)
|
63
|
+
errored_file = full_path_of_file_from_error(e)
|
36
64
|
|
37
|
-
register_acceptors_as_errors(e)
|
38
65
|
# register all the decendent acceptors as stubs with errors
|
66
|
+
register_acceptors_as_errors(e)
|
39
67
|
|
40
68
|
notify_feature(errored_file)
|
41
69
|
$LOADED_FEATURES.each { |f| notify_feature(f) }
|
@@ -45,51 +73,6 @@ module Zeus
|
|
45
73
|
sleep
|
46
74
|
end
|
47
75
|
|
48
|
-
def run(close_parent_sockets = false)
|
49
|
-
@pid = fork {
|
50
|
-
# This is only passed to the top-level stage, from Server#run, not sub-stages.
|
51
|
-
@server.__CHILD__close_parent_sockets if close_parent_sockets
|
52
|
-
|
53
|
-
$0 = "zeus spawner: #{@name}"
|
54
|
-
@server.__CHILD__pid_has_ppid(Process.pid, Process.ppid)
|
55
|
-
|
56
|
-
Zeus.ui.as_zeus("starting spawner `#{@name}`")
|
57
|
-
trap("INT") {
|
58
|
-
Zeus.ui.as_zeus("killing spawner `#{@name}`")
|
59
|
-
exit 0
|
60
|
-
}
|
61
|
-
|
62
|
-
begin
|
63
|
-
@actions.each(&:call)
|
64
|
-
rescue => e
|
65
|
-
handle_load_error(e)
|
66
|
-
end
|
67
|
-
|
68
|
-
pids = {}
|
69
|
-
@stages.each do |stage|
|
70
|
-
pids[stage.run] = stage
|
71
|
-
end
|
72
|
-
|
73
|
-
Thread.new {
|
74
|
-
$LOADED_FEATURES.each { |f| notify_feature(f) }
|
75
|
-
}
|
76
|
-
|
77
|
-
loop do
|
78
|
-
begin
|
79
|
-
pid = Process.wait
|
80
|
-
rescue Errno::ECHILD
|
81
|
-
raise HasNoChildren.new("Stage `#{@name}` - All terminal nodes must be acceptors")
|
82
|
-
end
|
83
|
-
stage = pids[pid]
|
84
|
-
pids[stage.run] = stage
|
85
|
-
end
|
86
|
-
}
|
87
|
-
currpid = Process.pid
|
88
|
-
at_exit { Process.kill(9, @pid) if Process.pid == currpid rescue nil }
|
89
|
-
@pid
|
90
|
-
end
|
91
|
-
|
92
76
|
end
|
93
|
-
|
94
77
|
end
|
95
78
|
end
|
data/lib/zeus/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zeus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -35,10 +35,12 @@ files:
|
|
35
35
|
- lib/zeus/dsl.rb
|
36
36
|
- lib/zeus/server.rb
|
37
37
|
- lib/zeus/server/acceptor.rb
|
38
|
+
- lib/zeus/server/acceptor_error_state.rb
|
38
39
|
- lib/zeus/server/acceptor_registration_monitor.rb
|
39
40
|
- lib/zeus/server/client_handler.rb
|
40
41
|
- lib/zeus/server/file_monitor.rb
|
41
42
|
- lib/zeus/server/file_monitor/fsevent.rb
|
43
|
+
- lib/zeus/server/forked_process.rb
|
42
44
|
- lib/zeus/server/process_tree.rb
|
43
45
|
- lib/zeus/server/process_tree_monitor.rb
|
44
46
|
- lib/zeus/server/stage.rb
|