Module: Zeus
- Defined in:
- lib/zeus.rb,
lib/zeus/m.rb,
lib/zeus/plan.rb,
lib/zeus/rails.rb,
lib/zeus/version.rb,
lib/zeus/load_tracking.rb,
lib/zeus/m/test_method.rb,
lib/zeus/m/test_collection.rb
Defined Under Namespace
Modules: M Classes: LoadTracking, Plan, Rails
Constant Summary collapse
- VERSION =
"0.16.0"
Class Attribute Summary collapse
-
.dummy_tty ⇒ Object
Returns the value of attribute dummy_tty.
-
.master_socket ⇒ Object
Returns the value of attribute master_socket.
-
.plan ⇒ Object
Returns the value of attribute plan.
Class Method Summary collapse
- .boot_steps(identifier) ⇒ Object
- .go(identifier = :boot) ⇒ Object
-
.setup_dummy_tty! ⇒ Object
this is totally asinine, but readline gets super confused when it’s required at a time when stdin or stdout is not connected to a TTY, no matter what we do to tell it otherwise later.
- .setup_master_socket! ⇒ Object
Class Attribute Details
.dummy_tty ⇒ Object
Returns the value of attribute dummy_tty.
19 20 21 |
# File 'lib/zeus.rb', line 19 def dummy_tty @dummy_tty end |
.master_socket ⇒ Object
Returns the value of attribute master_socket.
19 20 21 |
# File 'lib/zeus.rb', line 19 def master_socket @master_socket end |
.plan ⇒ Object
Returns the value of attribute plan.
19 20 21 |
# File 'lib/zeus.rb', line 19 def plan @plan end |
Class Method Details
.boot_steps(identifier) ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/zeus.rb', line 54 def boot_steps(identifier) while true boot_step = catch(:boot_step) do $0 = "zeus slave: #{identifier}" setup_dummy_tty! master = setup_master_socket! feature_pipe_r, feature_pipe_w = IO.pipe # I need to give the master a way to talk to me exclusively local, remote = UNIXSocket.pair(Socket::SOCK_STREAM) master.send_io(remote) # Now I need to tell the master about my PID and ID local.write "P:#{Process.pid}:#{@parent_pid || 0}:#{identifier}\0" local.send_io(feature_pipe_r) feature_pipe_r.close Zeus::LoadTracking.set_feature_pipe(feature_pipe_w) run_action(local, identifier) # We are now 'connected'. From this point, we may receive requests to fork. children = Set.new while true = local.recv(2**16) # Reap any child runners or slaves that might have exited in # the meantime. Note that reaping them like this can leave <=1 # zombie process per slave around while the slave waits for a # new command. children.each do |pid| children.delete(pid) if Process.waitpid(pid, Process::WNOHANG) end .split("\0").each do |new_identifier| new_identifier =~ /^(.):(.*)/ code, ident = $1, $2 forked_from = Process.pid pid = fork if pid # We're in the parent. Record the child: children << pid elsif code == "S" # Child, supposed to start another step: @parent_pid = forked_from Zeus::LoadTracking.clear_feature_pipe throw(:boot_step, ident.to_sym) else # Child, supposed to run a command: @parent_pid = forked_from Zeus::LoadTracking.clear_feature_pipe return [ident.to_sym, local] end end end end identifier = boot_step end end |
.go(identifier = :boot) ⇒ Object
44 45 46 47 48 49 50 51 52 |
# File 'lib/zeus.rb', line 44 def go(identifier=:boot) # Thanks to the magic of fork, this following line will return # many times: Every time the parent step receives a request to # run a command. if run_command = boot_steps(identifier) ident, local = run_command return command(ident, local) end end |
.setup_dummy_tty! ⇒ Object
this is totally asinine, but readline gets super confused when it’s required at a time when stdin or stdout is not connected to a TTY, no matter what we do to tell it otherwise later. So we create a dummy TTY in case readline is required.
Yup.
27 28 29 30 31 32 33 34 35 |
# File 'lib/zeus.rb', line 27 def setup_dummy_tty! return if self.dummy_tty master, self.dummy_tty = PTY.send(:open) Thread.new { loop { master.read(1024) } } STDIN.reopen(dummy_tty) STDOUT.reopen(dummy_tty) end |
.setup_master_socket! ⇒ Object
37 38 39 40 41 42 |
# File 'lib/zeus.rb', line 37 def setup_master_socket! return master_socket if master_socket fd = ENV['ZEUS_MASTER_FD'].to_i self.master_socket = UNIXSocket.for_fd(fd) end |