zeus 0.2.3 → 0.2.4
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/TODO.md +0 -5
- data/lib/zeus/cli.rb +2 -0
- data/lib/zeus/client.rb +6 -1
- data/lib/zeus/server.rb +2 -2
- data/lib/zeus/server/acceptor.rb +13 -5
- data/lib/zeus/server/acceptor_registration_monitor.rb +36 -2
- data/lib/zeus/server/client_handler.rb +48 -16
- data/lib/zeus/server/file_monitor/fsevent.rb +2 -2
- data/lib/zeus/server/stage.rb +3 -1
- data/lib/zeus/version.rb +1 -1
- metadata +2 -2
data/TODO.md
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
## TODO (roughly prioritized)
|
2
2
|
|
3
|
-
* After an acceptor is killed, attempting to request that command while it is reloading causes a server error.
|
4
3
|
* Make sure that when a command process's connection is dropped, it is killed
|
5
4
|
* less leaky handling of at_exit pid killing
|
6
|
-
* Instead of exiting when requesting an as-yet-unbooted acceptor, wait until it's available then run.
|
7
5
|
* Refactor, refactor, refactor...
|
8
|
-
* Make sure client connection requests are handled immediately (Chunk the select loop)
|
9
|
-
* Don't fork to handshake client to acceptor
|
10
|
-
* Eliminate the client-side exit lag for zeus commands.
|
11
6
|
* Support other frameworks?
|
12
7
|
* Figure out how to run full test suites without multiple env loads
|
13
8
|
|
data/lib/zeus/cli.rb
CHANGED
@@ -17,6 +17,8 @@ module Zeus
|
|
17
17
|
D
|
18
18
|
# method_option "rails", type: :string, banner: "Use the rails template instead of auto-detecting based on project contents"
|
19
19
|
def init
|
20
|
+
require 'fileutils'
|
21
|
+
|
20
22
|
if File.exist?(".zeus.rb")
|
21
23
|
Zeus.ui.error ".zeus.rb already exists at #{Dir.pwd}/.zeus.rb"
|
22
24
|
exit 1
|
data/lib/zeus/client.rb
CHANGED
@@ -69,7 +69,12 @@ module Zeus
|
|
69
69
|
def handle_stdin(buffer)
|
70
70
|
input = $stdin.readpartial(4096, buffer)
|
71
71
|
input.scan(SIGNAL_REGEX).each { |signal|
|
72
|
-
|
72
|
+
begin
|
73
|
+
Process.kill(SIGNALS[signal], pid)
|
74
|
+
rescue Errno::ESRCH
|
75
|
+
# we're trying to kill a process that died. Just quit.
|
76
|
+
exit
|
77
|
+
end
|
73
78
|
}
|
74
79
|
@master << input
|
75
80
|
end
|
data/lib/zeus/server.rb
CHANGED
data/lib/zeus/server/acceptor.rb
CHANGED
@@ -22,7 +22,7 @@ module Zeus
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def registration_data(pid)
|
25
|
-
{pid: pid, commands: [name, *aliases], description: description}.to_json
|
25
|
+
{type: 'registration', pid: pid, commands: [name, *aliases], description: description}.to_json
|
26
26
|
end
|
27
27
|
|
28
28
|
def descendent_acceptors
|
@@ -66,9 +66,12 @@ module Zeus
|
|
66
66
|
exit 0
|
67
67
|
}
|
68
68
|
|
69
|
-
|
70
|
-
|
71
|
-
|
69
|
+
# Apparently threads don't continue in forks.
|
70
|
+
Thread.new {
|
71
|
+
$LOADED_FEATURES.each do |f|
|
72
|
+
@server.w_feature "#{pid}:#{f}"
|
73
|
+
end
|
74
|
+
}
|
72
75
|
|
73
76
|
loop do
|
74
77
|
prefork_action!
|
@@ -88,9 +91,14 @@ module Zeus
|
|
88
91
|
Process.detach(child)
|
89
92
|
terminal.close
|
90
93
|
end
|
94
|
+
|
91
95
|
}
|
92
96
|
currpid = Process.pid
|
93
|
-
at_exit {
|
97
|
+
at_exit {
|
98
|
+
if Process.pid == currpid
|
99
|
+
Process.kill(9, pid) rescue nil
|
100
|
+
end
|
101
|
+
}
|
94
102
|
pid
|
95
103
|
end
|
96
104
|
|
@@ -3,25 +3,59 @@ module Zeus
|
|
3
3
|
class AcceptorRegistrationMonitor
|
4
4
|
|
5
5
|
def datasource ; @reg_monitor ; end
|
6
|
-
def on_datasource_event ;
|
6
|
+
def on_datasource_event ; handle_message ; end
|
7
7
|
|
8
8
|
def initialize
|
9
9
|
@reg_monitor, @reg_acceptor = UNIXSocket.pair
|
10
10
|
@acceptors = []
|
11
|
+
@pings = {}
|
11
12
|
end
|
12
13
|
|
13
14
|
AcceptorStub = Struct.new(:pid, :socket, :commands, :description)
|
14
15
|
|
15
|
-
def
|
16
|
+
def handle_message
|
16
17
|
io = @reg_monitor.recv_io
|
17
18
|
|
18
19
|
data = JSON.parse(io.readline.chomp)
|
20
|
+
type = data['type']
|
21
|
+
|
22
|
+
case type
|
23
|
+
when 'wait' ; handle_wait(io, data)
|
24
|
+
when 'registration' ; handle_registration(io, data)
|
25
|
+
when 'deregistration' ; handle_deregistration(io, data)
|
26
|
+
else raise "invalid message"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def handle_wait(io, data)
|
31
|
+
command = data['command'].to_s
|
32
|
+
@pings[command] ||= []
|
33
|
+
@pings[command] << io
|
34
|
+
end
|
35
|
+
|
36
|
+
def handle_deregistration(io, data)
|
37
|
+
pid = data['pid'].to_i
|
38
|
+
@acceptors.reject!{|acc|acc.pid == pid}
|
39
|
+
end
|
40
|
+
|
41
|
+
def handle_registration(io, data)
|
19
42
|
pid = data['pid'].to_i
|
20
43
|
commands = data['commands']
|
21
44
|
description = data['description']
|
22
45
|
|
23
46
|
@acceptors.reject!{|ac|ac.commands == commands}
|
24
47
|
@acceptors << AcceptorStub.new(pid, io, commands, description)
|
48
|
+
notify_pings_for_commands(commands)
|
49
|
+
end
|
50
|
+
|
51
|
+
def notify_pings_for_commands(commands)
|
52
|
+
(commands || []).each do |command|
|
53
|
+
(@pings[command.to_s] || []).each do |ping|
|
54
|
+
ping.puts "ready\n"
|
55
|
+
ping.close
|
56
|
+
end
|
57
|
+
@pings[command.to_s] = nil
|
58
|
+
end
|
25
59
|
end
|
26
60
|
|
27
61
|
def find_acceptor_for_command(command)
|
@@ -39,9 +39,25 @@ module Zeus
|
|
39
39
|
|
40
40
|
def handle_server_connection
|
41
41
|
s_client = @server.accept
|
42
|
-
|
42
|
+
|
43
|
+
# 1
|
44
|
+
data = JSON.parse(s_client.readline.chomp)
|
45
|
+
command, arguments = data.values_at('command', 'arguments')
|
46
|
+
|
47
|
+
# 2
|
48
|
+
client_terminal = s_client.recv_io
|
49
|
+
|
50
|
+
Thread.new {
|
51
|
+
loop do
|
52
|
+
pid = fork { handshake_client_to_acceptor(s_client, command, arguments, client_terminal) ; exit }
|
53
|
+
Process.wait(pid)
|
54
|
+
break unless $?.exitstatus == REATTEMPT_HANDSHAKE
|
55
|
+
end
|
56
|
+
}
|
43
57
|
end
|
44
58
|
|
59
|
+
REATTEMPT_HANDSHAKE = 204
|
60
|
+
|
45
61
|
NoSuchCommand = Class.new(Exception)
|
46
62
|
AcceptorNotBooted = Class.new(Exception)
|
47
63
|
ApplicationLoadFailed = Class.new(Exception)
|
@@ -53,6 +69,22 @@ module Zeus
|
|
53
69
|
s_client.close
|
54
70
|
end
|
55
71
|
|
72
|
+
def wait_for_acceptor(s_client, client_terminal, command, msg)
|
73
|
+
s_client << "0\n"
|
74
|
+
client_terminal << "[zeus] #{msg}\n"
|
75
|
+
|
76
|
+
regmsg = {type: 'wait', command: command}
|
77
|
+
|
78
|
+
s, r = UNIXSocket.pair
|
79
|
+
@reg_monitor.acceptor_registration_socket.send_io(r)
|
80
|
+
s << "#{regmsg.to_json}\n"
|
81
|
+
|
82
|
+
s.readline # wait
|
83
|
+
s.close
|
84
|
+
|
85
|
+
exit REATTEMPT_HANDSHAKE
|
86
|
+
end
|
87
|
+
|
56
88
|
# client clienthandler acceptor
|
57
89
|
# 1 ----------> | {command: String, arguments: [String]}
|
58
90
|
# 2 ----------> | Terminal IO
|
@@ -60,14 +92,7 @@ module Zeus
|
|
60
92
|
# 4 -----------> | Arguments (json array)
|
61
93
|
# 5 <----------- | pid
|
62
94
|
# 6 <--------- | pid
|
63
|
-
def handshake_client_to_acceptor(s_client)
|
64
|
-
# 1
|
65
|
-
data = JSON.parse(s_client.readline.chomp)
|
66
|
-
command, arguments = data.values_at('command', 'arguments')
|
67
|
-
|
68
|
-
# 2
|
69
|
-
client_terminal = s_client.recv_io
|
70
|
-
|
95
|
+
def handshake_client_to_acceptor(s_client, command, arguments, client_terminal)
|
71
96
|
# 3
|
72
97
|
unless @acceptor_commands.include?(command.to_s)
|
73
98
|
return exit_with_message(
|
@@ -76,17 +101,24 @@ module Zeus
|
|
76
101
|
end
|
77
102
|
acceptor = @reg_monitor.find_acceptor_for_command(command)
|
78
103
|
unless acceptor
|
79
|
-
|
80
|
-
s_client, client_terminal,
|
81
|
-
"
|
104
|
+
wait_for_acceptor(
|
105
|
+
s_client, client_terminal, command,
|
106
|
+
"waiting for `#{command}` to finish booting...")
|
82
107
|
end
|
83
108
|
usock = UNIXSocket.for_fd(acceptor.socket.fileno)
|
84
109
|
if usock.closed?
|
85
|
-
|
86
|
-
s_client, client_terminal,
|
87
|
-
"`#{command}`
|
110
|
+
wait_for_acceptor(
|
111
|
+
s_client, client_terminal, command,
|
112
|
+
"waiting for `#{command}` to finish reloading dependencies...")
|
113
|
+
end
|
114
|
+
begin
|
115
|
+
usock.send_io(client_terminal)
|
116
|
+
rescue Errno::EPIPE
|
117
|
+
wait_for_acceptor(
|
118
|
+
s_client, client_terminal, command,
|
119
|
+
"waiting for `#{command}` to finish reloading dependencies...")
|
88
120
|
end
|
89
|
-
|
121
|
+
|
90
122
|
|
91
123
|
Zeus.ui.info "accepting connection for #{command}"
|
92
124
|
|
data/lib/zeus/server/stage.rb
CHANGED
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.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-08-
|
12
|
+
date: 2012-08-03 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Zeus preloads pretty much everything you'll ever want to use in development.
|
15
15
|
email:
|