zeus 0.4.5 → 0.4.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.
@@ -0,0 +1,42 @@
1
+ module Zeus
2
+ class Server
3
+ class Stage
4
+
5
+ module ErrorState
6
+ def handle_load_error(e)
7
+ errored_file = full_path_of_file_from_error(e)
8
+
9
+ # register all the decendent acceptors as stubs with errors
10
+ register_acceptors_as_errors(e)
11
+
12
+ feature_notifier.notify_feature(errored_file)
13
+ feature_notifier.notify_new_features
14
+
15
+ # we do not need to do anything. We wait, until a dependency changes.
16
+ # At that point, we get killed and restarted.
17
+ sleep
18
+ end
19
+
20
+ private
21
+
22
+ def full_path_of_file_from_error(e)
23
+ errored_file = e.backtrace[0].scan(/(.+?):\d+:in/)[0][0]
24
+
25
+ # handle relative paths
26
+ unless errored_file =~ /^\//
27
+ errored_file = File.expand_path(errored_file, Dir.pwd)
28
+ end
29
+ end
30
+
31
+ def register_acceptors_as_errors(e)
32
+ descendent_acceptors.each do |acc|
33
+ acc = acc.extend(Acceptor::ErrorState)
34
+ acc.error = e
35
+ acc.run
36
+ end
37
+ end
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,38 @@
1
+ module Zeus
2
+ class Server
3
+ class Stage
4
+ class FeatureNotifier
5
+
6
+ def initialize(server, stage_name)
7
+ @server = server
8
+ @stage_name = stage_name
9
+ end
10
+
11
+ def notify_new_features
12
+ new_features = newly_loaded_features()
13
+ $previously_loaded_features ||= []
14
+ $previously_loaded_features |= new_features
15
+ Thread.new {
16
+ new_features.each { |f| notify_feature(f) }
17
+ }
18
+ end
19
+
20
+ def notify_feature(feature)
21
+ @server.__CHILD__stage_has_feature(@stage_name, feature)
22
+ end
23
+
24
+ private
25
+
26
+ def newly_loaded_features
27
+ old_features = defined?($previously_loaded_features) ? $previously_loaded_features : []
28
+ ($LOADED_FEATURES + @server.extra_features) - old_features
29
+ end
30
+
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+
37
+
38
+
@@ -1,3 +1,3 @@
1
1
  module Zeus
2
- VERSION = "0.4.5"
2
+ VERSION = "0.4.6"
3
3
  end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ require 'stringio'
4
+
5
+ module Zeus
6
+ describe ErrorPrinter do
7
+
8
+ let(:error) {
9
+ begin
10
+ raise
11
+ rescue => e
12
+ e
13
+ end
14
+ }
15
+
16
+ it 'prints an error just like ruby does by default' do
17
+ io = StringIO.new
18
+ ErrorPrinter.new(error).write_to(io)
19
+ io.rewind
20
+ lines = io.readlines
21
+ lines[0].should =~ /^[^\s]*error_printer_spec.rb:\d+:in `.+': \(RuntimeError\)$/
22
+ lines[1].should =~ /^\tfrom .*\.rb:\d+:in `.*'$/
23
+ lines.size.should > 5
24
+ end
25
+
26
+ end
27
+ end
@@ -7,22 +7,29 @@ describe "Integration" do
7
7
 
8
8
  context "in a non-rails project with a .zeus.rb" do
9
9
  it "starts the zeus server and responds to commands" do
10
- write ".zeus.rb", <<-RUBY
11
- Zeus::Server.define! do
12
- stage :foo do
13
- command :bar do
14
- puts "YES"
15
- end
16
- end
17
- end
18
- RUBY
19
-
10
+ bar_setup("puts 'YES'")
20
11
  start, run = start_and_run("bar")
21
12
  start.should include "spawner `foo`"
22
13
  start.should include "acceptor `bar`"
23
14
  run.should == ["YES\r\n"]
24
15
  end
25
16
 
17
+ it "receives ARGV after command" do
18
+ bar_setup("puts ARGV.join(', ')")
19
+ start, run = start_and_run("bar 1 '2 3 4' --123")
20
+ run.should == ["1, 2 3 4, --123\r\n"]
21
+ end
22
+
23
+ it "cam exist with 0" do
24
+ bar_setup("exit 0")
25
+ start_and_run("bar")
26
+ end
27
+
28
+ it "can exist with non-0" do
29
+ bar_setup("exit 1")
30
+ start_and_run("bar", :fail => true)
31
+ end
32
+
26
33
  it "can run via command alias" do
27
34
  write ".zeus.rb", <<-RUBY
28
35
  Zeus::Server.define! do
@@ -43,6 +50,18 @@ describe "Integration" do
43
50
 
44
51
  private
45
52
 
53
+ def bar_setup(inner)
54
+ write ".zeus.rb", <<-RUBY
55
+ Zeus::Server.define! do
56
+ stage :foo do
57
+ command :bar do
58
+ #{inner}
59
+ end
60
+ end
61
+ end
62
+ RUBY
63
+ end
64
+
46
65
  def zeus(command, options={})
47
66
  command = zeus_command(command)
48
67
  result = `#{command}`
@@ -62,11 +81,11 @@ describe "Integration" do
62
81
  end
63
82
  end
64
83
 
65
- def start_and_run(commands)
84
+ def start_and_run(commands, options={})
66
85
  start_output = ""
67
86
  t1 = Thread.new { record_start(start_output) }
68
87
  sleep 0.1
69
- run_output = [*commands].map{ |cmd| zeus(cmd) }
88
+ run_output = [*commands].map{ |cmd| zeus(cmd, options) }
70
89
  sleep 0.2
71
90
  t1.kill
72
91
  [start_output, run_output]
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.4.5
4
+ version: 0.4.6
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-16 00:00:00.000000000 Z
12
+ date: 2012-08-20 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Boot any rails app in under a second
15
15
  email:
@@ -27,13 +27,20 @@ files:
27
27
  - README.md
28
28
  - Rakefile
29
29
  - bin/zeus
30
+ - docs/acceptor_registration.md
31
+ - docs/client_server_handshake.md
30
32
  - ext/fsevents-wrapper/fsevents-wrapper
31
33
  - ext/fsevents-wrapper/main.m
32
34
  - lib/thrud.rb
33
35
  - lib/zeus.rb
34
36
  - lib/zeus/cli.rb
35
37
  - lib/zeus/client.rb
36
- - lib/zeus/dsl.rb
38
+ - lib/zeus/client/winsize.rb
39
+ - lib/zeus/error_printer.rb
40
+ - lib/zeus/plan.rb
41
+ - lib/zeus/plan/acceptor.rb
42
+ - lib/zeus/plan/node.rb
43
+ - lib/zeus/plan/stage.rb
37
44
  - lib/zeus/server.rb
38
45
  - lib/zeus/server/acceptor.rb
39
46
  - lib/zeus/server/acceptor_registration_monitor.rb
@@ -41,14 +48,16 @@ files:
41
48
  - lib/zeus/server/command_runner.rb
42
49
  - lib/zeus/server/file_monitor.rb
43
50
  - lib/zeus/server/file_monitor/fsevent.rb
44
- - lib/zeus/server/forked_process.rb
45
51
  - lib/zeus/server/load_tracking.rb
46
52
  - lib/zeus/server/process_tree_monitor.rb
47
53
  - lib/zeus/server/stage.rb
54
+ - lib/zeus/server/stage/error_state.rb
55
+ - lib/zeus/server/stage/feature_notifier.rb
48
56
  - lib/zeus/templates/rails.rb
49
57
  - lib/zeus/ui.rb
50
58
  - lib/zeus/version.rb
51
59
  - spec/cli_spec.rb
60
+ - spec/error_printer_spec.rb
52
61
  - spec/integration_spec.rb
53
62
  - spec/server/file_monitor/fsevent_spec.rb
54
63
  - spec/server/load_tracking_spec.rb
@@ -84,6 +93,7 @@ summary: Zeus is an intelligent preloader for ruby applications. It allows norma
84
93
  development tasks to be run in a fraction of a second.
85
94
  test_files:
86
95
  - spec/cli_spec.rb
96
+ - spec/error_printer_spec.rb
87
97
  - spec/integration_spec.rb
88
98
  - spec/server/file_monitor/fsevent_spec.rb
89
99
  - spec/server/load_tracking_spec.rb
@@ -1,154 +0,0 @@
1
- require 'set'
2
-
3
- module Zeus
4
- module DSL
5
-
6
- class Evaluator
7
- def stage(name, &b)
8
- stage = DSL::Stage.new(name)
9
- stage.root = true
10
- stage.instance_eval(&b)
11
- stage
12
- end
13
- end
14
-
15
- class Node
16
- attr_reader :name, :stages, :features
17
- attr_accessor :pid, :root
18
-
19
- def initialize(name)
20
- @name = name
21
- @stages = []
22
- @features = Set.new # hash might be faster than ruby's inane impl of set.
23
- end
24
-
25
- def stage_has_feature(name, file)
26
- node_for_name(name).features << file
27
- end
28
-
29
- def stage_has_pid(name, pid)
30
- node_for_name(name).pid = pid
31
- end
32
-
33
- def kill_nodes_with_feature(file)
34
- if features.include?(file)
35
- if root
36
- Zeus.ui.error "One of zeus's dependencies changed. Not killing zeus. You may have to restart the server."
37
- else
38
- kill!
39
- end
40
- else
41
- stages.each do |child|
42
- child.kill_nodes_with_feature(file)
43
- end
44
- end
45
- end
46
-
47
- # We send STOP before actually killing the processes here.
48
- # This is to prevent parents from respawning before all the children
49
- # are killed. This prevents a race condition.
50
- def kill!
51
- Process.kill("STOP", pid) if pid
52
- # Protected methods don't work with each(&:m) notation.
53
- stages.each { |stage| stage.kill! }
54
- old_pid = pid
55
- self.pid = nil
56
- Process.kill("KILL", old_pid) if old_pid
57
- end
58
-
59
- private
60
-
61
- def node_for_name(name)
62
- @nodes_by_name ||= __nodes_by_name
63
- @nodes_by_name[name]
64
- end
65
-
66
- def __nodes_by_name
67
- nodes = {name => self}
68
- stages.each do |child|
69
- nodes.merge!(child.__nodes_by_name)
70
- end
71
- nodes
72
- end ; protected :__nodes_by_name
73
-
74
- end
75
-
76
- class Acceptor < Node
77
-
78
- attr_reader :name, :aliases, :description, :action
79
- def initialize(name, aliases, description, &b)
80
- super(name)
81
- @description = description
82
- @aliases = aliases
83
- @action = b
84
- end
85
-
86
- # ^ configuration
87
- # V later use
88
-
89
- def commands
90
- [name, *aliases].map(&:to_s)
91
- end
92
-
93
- def acceptors
94
- self
95
- end
96
-
97
- def to_process_object(server)
98
- Zeus::Server::Acceptor.new(server).tap do |stage|
99
- stage.name = @name
100
- stage.aliases = @aliases
101
- stage.action = @action
102
- stage.description = @description
103
- end
104
- end
105
-
106
- end
107
-
108
- class Stage < Node
109
-
110
- attr_reader :actions
111
- def initialize(name)
112
- super(name)
113
- @actions = []
114
- end
115
-
116
- def action(&b)
117
- @actions << b
118
- self
119
- end
120
-
121
- def desc(desc)
122
- @desc = desc
123
- end
124
-
125
- def stage(name, &b)
126
- @stages << DSL::Stage.new(name).tap { |s| s.instance_eval(&b) }
127
- self
128
- end
129
-
130
- def command(name, *aliases, &b)
131
- @stages << DSL::Acceptor.new(name, aliases, @desc, &b)
132
- @desc = nil
133
- self
134
- end
135
-
136
- # ^ configuration
137
- # V later use
138
-
139
- def acceptors
140
- stages.map(&:acceptors).flatten
141
- end
142
-
143
- def to_process_object(server)
144
- Zeus::Server::Stage.new(server).tap do |stage|
145
- stage.name = @name
146
- stage.stages = @stages.map { |stage| stage.to_process_object(server) }
147
- stage.actions = @actions
148
- end
149
- end
150
-
151
- end
152
-
153
- end
154
- end
@@ -1,98 +0,0 @@
1
- module Zeus
2
- class Server
3
- # base class for Stage and Acceptor
4
- class ForkedProcess
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__stage_has_feature(@name, 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 notify_started
25
- @server.__CHILD__stage_starting_with_pid(@name, Process.pid)
26
- Zeus.ui.info("starting #{process_type} `#{@name}`")
27
- end
28
-
29
- def notify_terminated
30
- # @server.__CHILD__stage_terminating(@name)
31
- Zeus.ui.info("killing #{process_type} `#{@name}`")
32
- end
33
-
34
- def setup_forked_process(close_parent_sockets)
35
- @server.__CHILD__close_parent_sockets if close_parent_sockets
36
-
37
- notify_started
38
-
39
- $0 = "zeus #{process_type}: #{@name}"
40
-
41
- trap("INT") { exit }
42
- trap("TERM") {
43
- notify_terminated
44
- exit
45
- }
46
-
47
- defined?(ActiveRecord::Base) and ActiveRecord::Base.clear_all_connections!
48
-
49
- end
50
-
51
- def newly_loaded_features
52
- old_features = defined?($previously_loaded_features) ? $previously_loaded_features : []
53
- ($LOADED_FEATURES + @server.extra_features) - old_features
54
- end
55
-
56
- def runloop!
57
- raise NotImplementedError
58
- end
59
-
60
- def before_setup
61
- end
62
-
63
- def after_setup
64
- end
65
-
66
- def notify_new_features
67
- new_features = newly_loaded_features()
68
- $previously_loaded_features ||= []
69
- $previously_loaded_features |= new_features
70
- Thread.new {
71
- new_features.each { |f| notify_feature(f) }
72
- }
73
- end
74
-
75
- def after_notify
76
- end
77
-
78
- # TODO: This just got really ugly and needs a refactor more than ever.
79
- def run(close_parent_sockets = false)
80
- @pid = fork {
81
- before_setup
82
- setup_forked_process(close_parent_sockets)
83
-
84
- Zeus.run_after_fork!
85
-
86
- after_setup
87
- notify_new_features
88
-
89
- after_notify
90
- runloop!
91
- }
92
- end
93
-
94
- end
95
-
96
- end
97
- end
98
-