einhorn 0.7.0 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -78,6 +78,10 @@ class UpgradeTests < EinhornIntegrationTestCase
78
78
  state = YAML.load(resp['message'])
79
79
  assert_equal(1, state[:state][:children].count)
80
80
 
81
+ child = state[:state][:children].first.last
82
+ assert_in_delta(child[:pinged_at], Time.now, 60)
83
+ assert_equal("id-1", child[:pinged_request_id])
84
+
81
85
  process.terminate
82
86
  end
83
87
  end
@@ -154,4 +158,47 @@ class UpgradeTests < EinhornIntegrationTestCase
154
158
  end
155
159
  end
156
160
  end
161
+
162
+ describe "with --signal-timeout" do
163
+ before do
164
+ @dir = prepare_fixture_directory('signal_timeout')
165
+ @port = find_free_port
166
+ @server_program = File.join(@dir, "sleepy_server.rb")
167
+ @socket_path = File.join(@dir, "einhorn.sock")
168
+ end
169
+
170
+ after { cleanup_fixtured_directories }
171
+
172
+ it 'issues a SIGKILL to outdated children when signal-timeout has passed' do
173
+ signal_timeout = 2
174
+ sleep_for = 10
175
+ cmd = %W{
176
+ einhorn
177
+ -b 127.0.0.1:#{@port}
178
+ -d #{@socket_path}
179
+ --signal-timeout #{signal_timeout}
180
+ -- ruby #{@server_program}
181
+ }
182
+
183
+ with_running_einhorn(cmd, env: ENV.to_h.merge({'TRAP_SLEEP' => sleep_for.to_s})) do |process|
184
+ wait_for_open_port
185
+ client = Einhorn::Client.for_path(@socket_path)
186
+ einhornsh(%W{-d #{@socket_path} -e upgrade})
187
+
188
+ state = get_state(client)
189
+ assert_equal(2, state[:children].count)
190
+ signaled_children = state[:children].select{|_,c| c[:signaled].length > 0}
191
+ assert_equal(1, signaled_children.length)
192
+
193
+ sleep(signal_timeout * 2)
194
+
195
+ state = get_state(client)
196
+ assert_equal(1, state[:children].count)
197
+ signaled_children = state[:children].select{|_,c| c[:signaled].length > 0}
198
+ assert_equal(0, signaled_children.length)
199
+
200
+ process.terminate
201
+ end
202
+ end
203
+ end
157
204
  end
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ raise 'This worker has an error during preload'
4
+
5
+ def einhorn_main
6
+
7
+ end
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ def einhorn_main
4
+ sleep 1
5
+ end
@@ -10,7 +10,7 @@ class EinhornTest < EinhornTestCase
10
10
 
11
11
  it "correctly parses srv: arguments" do
12
12
  cmd = ['foo', 'srv:1.2.3.4:123,llama,test', 'bar']
13
- Einhorn.expects(:bind).once.with('1.2.3.4', '123', ['llama', 'test']).returns(4)
13
+ Einhorn.expects(:bind).once.with('1.2.3.4', '123', ['llama', 'test']).returns([4, 10087])
14
14
 
15
15
  Einhorn.socketify!(cmd)
16
16
 
@@ -19,7 +19,7 @@ class EinhornTest < EinhornTestCase
19
19
 
20
20
  it "correctly parses --opt=srv: arguments" do
21
21
  cmd = ['foo', '--opt=srv:1.2.3.4:456', 'baz']
22
- Einhorn.expects(:bind).once.with('1.2.3.4', '456', []).returns(5)
22
+ Einhorn.expects(:bind).once.with('1.2.3.4', '456', []).returns([5, 10088])
23
23
 
24
24
  Einhorn.socketify!(cmd)
25
25
 
@@ -28,7 +28,7 @@ class EinhornTest < EinhornTestCase
28
28
 
29
29
  it "uses the same fd number for the same server spec" do
30
30
  cmd = ['foo', '--opt=srv:1.2.3.4:8910', 'srv:1.2.3.4:8910']
31
- Einhorn.expects(:bind).once.with('1.2.3.4', '8910', []).returns(10)
31
+ Einhorn.expects(:bind).once.with('1.2.3.4', '8910', []).returns([10, 10089])
32
32
 
33
33
  Einhorn.socketify!(cmd)
34
34
 
@@ -55,4 +55,42 @@ class EinhornTest < EinhornTestCase
55
55
  assert(message.nil?)
56
56
  end
57
57
  end
58
+
59
+ describe ".preload" do
60
+ before do
61
+ Einhorn::State.preloaded = false
62
+ end
63
+
64
+ it "updates preload on success" do
65
+ Einhorn.stubs(:set_argv).returns
66
+ # preloads the sleep worker since it has einhorn main
67
+ Einhorn::State.path = "#{__dir__}/_lib/sleep_worker.rb"
68
+ assert_equal(false, Einhorn::State.preloaded)
69
+ Einhorn.preload
70
+ assert_equal(true, Einhorn::State.preloaded)
71
+ # Attempt another preload
72
+ Einhorn.preload
73
+ assert_equal(true, Einhorn::State.preloaded)
74
+ end
75
+
76
+ it "updates preload to failed with previous success" do
77
+ Einhorn.stubs(:set_argv).returns
78
+ Einhorn::State.path = "#{__dir__}/_lib/sleep_worker.rb"
79
+ assert_equal(false, Einhorn::State.preloaded)
80
+ Einhorn.preload
81
+ assert_equal(true, Einhorn::State.preloaded)
82
+ # Change path to bad worker and preload again, should be false
83
+ Einhorn::State.path = "#{__dir__}/_lib/bad_worker.rb"
84
+ Einhorn.preload
85
+ assert_equal(false, Einhorn::State.preloaded)
86
+ end
87
+
88
+ it "preload is false after failing" do
89
+ Einhorn.stubs(:set_argv).returns
90
+ Einhorn::State.path = "#{__dir__}/bad_worker.rb"
91
+ assert_equal(false, Einhorn::State.preloaded)
92
+ Einhorn.preload
93
+ assert_equal(false, Einhorn::State.preloaded)
94
+ end
95
+ end
58
96
  end
@@ -18,4 +18,118 @@ class CommandTest < EinhornTestCase
18
18
  Command.quieter
19
19
  end
20
20
  end
21
+
22
+ describe "resignal_timeout" do
23
+ it "does not kill any children" do
24
+ Einhorn::State.stubs(signal_timeout: 5 * 60)
25
+ Einhorn::State.stubs(children: {
26
+ 12345 => {last_signaled_at: nil},
27
+ 12346 => {signaled: Set.new(["USR1"]), last_signaled_at: Time.now - (2 * 60)},
28
+ })
29
+
30
+ Process.expects(:kill).never
31
+ Einhorn::Command.kill_expired_signaled_workers
32
+
33
+ refute(Einhorn::State.children[12346][:signaled].include?("KILL"), "Process was KILLed when it shouldn't have been")
34
+ end
35
+
36
+ it "KILLs stuck child processes" do
37
+ Time.stub :now, Time.at(0) do
38
+ Process.stub(:kill, true) do
39
+ Einhorn::State.stubs(signal_timeout: 60)
40
+ Einhorn::State.stubs(children: {
41
+ 12346 => {signaled: Set.new(["USR2"]), last_signaled_at: Time.now - (2 * 60)},
42
+ })
43
+
44
+ Einhorn::Command.kill_expired_signaled_workers
45
+
46
+ child = Einhorn::State.children[12346]
47
+ assert(child[:signaled].include?("KILL"), "Process was not KILLed as expected")
48
+ assert(child[:last_signaled_at] == Time.now, "The last_processed_at was not updated as expected")
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ describe "trigger_spinup?" do
55
+ it "is true by default" do
56
+ assert(Einhorn::Command.trigger_spinup?(1))
57
+ end
58
+
59
+ it "is false if unacked >= max_unacked" do
60
+ Einhorn::State.stubs(children: {12346 => {type: :worker, acked: false, signaled: Set.new}})
61
+ assert(Einhorn::Command.trigger_spinup?(1))
62
+ end
63
+
64
+ it "is false if capacity is exceeded" do
65
+ Einhorn::State.stubs(config: {max_upgrade_additional: 1, number: 1})
66
+ Einhorn::State.stubs(
67
+ children: {
68
+ 1 => {type: :worker, acked: true, signaled: Set.new},
69
+ 2 => {type: :worker, acked: true, signaled: Set.new},
70
+ 3 => {type: :worker, acked: true, signaled: Set.new},
71
+ }
72
+ )
73
+ refute(Einhorn::Command.trigger_spinup?(1))
74
+ end
75
+
76
+ it "is true if under capacity" do
77
+ Einhorn::State.stubs(config: {max_upgrade_additional: 2, number: 1})
78
+ Einhorn::State.stubs(children: {1 => {type: :worker, acked: true, signaled: Set.new}})
79
+ assert(Einhorn::Command.trigger_spinup?(1))
80
+ end
81
+ end
82
+
83
+ describe "replenish_gradually" do
84
+ it "does nothing if an outstanding spinup timer exists" do
85
+ Einhorn::TransientState.stubs(has_outstanding_spinup_timer: true)
86
+ Einhorn::Command.expects(:spinup).never
87
+ Einhorn::Command.replenish_gradually
88
+ end
89
+ it "does nothing if the worker pool is full" do
90
+ Einhorn::TransientState.stubs(has_outstanding_spinup_timer: false)
91
+ Einhorn::WorkerPool.stubs(missing_worker_count: 0)
92
+ Einhorn::Command.expects(:spinup).never
93
+ Einhorn::Command.replenish_gradually
94
+ end
95
+
96
+ it "does nothing if we have not reached the spinup interval" do
97
+ Einhorn::TransientState.stubs(has_outstanding_spinup_timer: false)
98
+ Einhorn::WorkerPool.stubs(missing_worker_count: 1)
99
+ Einhorn::State.stubs(last_spinup: Time.now)
100
+ Einhorn::Command.expects(:spinup).never
101
+ Einhorn::Command.replenish_gradually
102
+ end
103
+
104
+ it "calls trigger_spinup? if we have reached the spinup interval" do
105
+ Einhorn::TransientState.stubs(has_outstanding_spinup_timer: false)
106
+ Einhorn::State.stubs(config: {seconds: 1, max_unacked: 2, number: 1})
107
+ Einhorn::WorkerPool.stubs(missing_worker_count: 1)
108
+ Einhorn::State.stubs(last_spinup: Time.now - 2) # 2 seconds ago
109
+ Einhorn::Command.expects(:trigger_spinup?).with(2).returns(false)
110
+ Einhorn::Command.replenish_gradually
111
+ end
112
+
113
+ it "can handle sub-second spinup intervals" do
114
+ Einhorn::TransientState.stubs(has_outstanding_spinup_timer: false)
115
+ Einhorn::State.stubs(config: {seconds: 0.1, max_unacked: 2, number: 1})
116
+ Einhorn::WorkerPool.stubs(missing_worker_count: 1)
117
+ Einhorn::State.stubs(last_spinup: Time.now - 0.5) # Half a second ago
118
+ Einhorn::Command.stubs(trigger_spinup?: true)
119
+ Einhorn::Command.expects(:spinup)
120
+ Einhorn::Command.replenish_gradually
121
+ end
122
+
123
+ it "registers a timer to run again at spinup interval" do
124
+ Einhorn::TransientState.stubs(has_outstanding_spinup_timer: false)
125
+ Einhorn::State.stubs(config: {seconds: 0.1, max_unacked: 2, number: 1})
126
+ Einhorn::WorkerPool.stubs(missing_worker_count: 1)
127
+ Einhorn::State.stubs(last_spinup: Time.now - 1)
128
+ Einhorn::Command.stubs(trigger_spinup?: true)
129
+ Einhorn::Command.stubs(:spinup)
130
+ Einhorn::TransientState.expects(:has_outstanding_spinup_timer=).with(true)
131
+ Einhorn::Event::Timer.expects(:open).with(0.1)
132
+ Einhorn::Command.replenish_gradually
133
+ end
134
+ end
21
135
  end
metadata CHANGED
@@ -1,110 +1,111 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: einhorn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
5
- prerelease:
4
+ version: 0.8.2
6
5
  platform: ruby
7
6
  authors:
8
7
  - Greg Brockman
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2015-08-20 00:00:00.000000000 Z
11
+ date: 2020-10-29 00:00:00.000000000 Z
13
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
14
27
  - !ruby/object:Gem::Dependency
15
28
  name: rake
16
29
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
30
  requirements:
19
- - - ! '>='
31
+ - - ">="
20
32
  - !ruby/object:Gem::Version
21
33
  version: '0'
22
34
  type: :development
23
35
  prerelease: false
24
36
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
37
  requirements:
27
- - - ! '>='
38
+ - - ">="
28
39
  - !ruby/object:Gem::Version
29
40
  version: '0'
30
41
  - !ruby/object:Gem::Dependency
31
42
  name: pry
32
43
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
44
  requirements:
35
- - - ! '>='
45
+ - - ">="
36
46
  - !ruby/object:Gem::Version
37
47
  version: '0'
38
48
  type: :development
39
49
  prerelease: false
40
50
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
51
  requirements:
43
- - - ! '>='
52
+ - - ">="
44
53
  - !ruby/object:Gem::Version
45
54
  version: '0'
46
55
  - !ruby/object:Gem::Dependency
47
56
  name: minitest
48
57
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
58
  requirements:
51
- - - <
59
+ - - "<"
52
60
  - !ruby/object:Gem::Version
53
61
  version: '5.0'
54
62
  type: :development
55
63
  prerelease: false
56
64
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
65
  requirements:
59
- - - <
66
+ - - "<"
60
67
  - !ruby/object:Gem::Version
61
68
  version: '5.0'
62
69
  - !ruby/object:Gem::Dependency
63
70
  name: mocha
64
71
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
72
  requirements:
67
- - - ~>
73
+ - - "~>"
68
74
  - !ruby/object:Gem::Version
69
75
  version: '0.13'
70
76
  type: :development
71
77
  prerelease: false
72
78
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
79
  requirements:
75
- - - ~>
80
+ - - "~>"
76
81
  - !ruby/object:Gem::Version
77
82
  version: '0.13'
78
83
  - !ruby/object:Gem::Dependency
79
84
  name: chalk-rake
80
85
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
86
  requirements:
83
- - - ! '>='
87
+ - - ">="
84
88
  - !ruby/object:Gem::Version
85
89
  version: '0'
86
90
  type: :development
87
91
  prerelease: false
88
92
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
93
  requirements:
91
- - - ! '>='
94
+ - - ">="
92
95
  - !ruby/object:Gem::Version
93
96
  version: '0'
94
97
  - !ruby/object:Gem::Dependency
95
98
  name: subprocess
96
99
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
100
  requirements:
99
- - - ! '>='
101
+ - - ">="
100
102
  - !ruby/object:Gem::Version
101
103
  version: '0'
102
104
  type: :development
103
105
  prerelease: false
104
106
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
107
  requirements:
107
- - - ! '>='
108
+ - - ">="
108
109
  - !ruby/object:Gem::Version
109
110
  version: '0'
110
111
  description: Einhorn makes it easy to run multiple instances of an application server,
@@ -119,8 +120,8 @@ executables:
119
120
  extensions: []
120
121
  extra_rdoc_files: []
121
122
  files:
122
- - .gitignore
123
- - .travis.yml
123
+ - ".gitignore"
124
+ - ".travis.yml"
124
125
  - CONTRIBUTORS
125
126
  - Gemfile
126
127
  - History.txt
@@ -147,6 +148,8 @@ files:
147
148
  - lib/einhorn/event/loop_breaker.rb
148
149
  - lib/einhorn/event/persistent.rb
149
150
  - lib/einhorn/event/timer.rb
151
+ - lib/einhorn/prctl.rb
152
+ - lib/einhorn/prctl_linux.rb
150
153
  - lib/einhorn/third.rb
151
154
  - lib/einhorn/version.rb
152
155
  - lib/einhorn/worker.rb
@@ -156,11 +159,16 @@ files:
156
159
  - test/integration/_lib/fixtures/env_printer/env_printer.rb
157
160
  - test/integration/_lib/fixtures/exit_during_upgrade/exiting_server.rb
158
161
  - test/integration/_lib/fixtures/exit_during_upgrade/upgrade_reexec.rb
162
+ - test/integration/_lib/fixtures/pdeathsig_printer/pdeathsig_printer.rb
163
+ - test/integration/_lib/fixtures/signal_timeout/sleepy_server.rb
159
164
  - test/integration/_lib/fixtures/upgrade_project/upgrading_server.rb
160
165
  - test/integration/_lib/helpers.rb
161
166
  - test/integration/_lib/helpers/einhorn_helpers.rb
167
+ - test/integration/pdeathsig.rb
162
168
  - test/integration/startup.rb
163
169
  - test/integration/upgrading.rb
170
+ - test/unit/_lib/bad_worker.rb
171
+ - test/unit/_lib/sleep_worker.rb
164
172
  - test/unit/einhorn.rb
165
173
  - test/unit/einhorn/client.rb
166
174
  - test/unit/einhorn/command.rb
@@ -170,43 +178,45 @@ files:
170
178
  homepage: https://github.com/stripe/einhorn
171
179
  licenses:
172
180
  - MIT
181
+ metadata: {}
173
182
  post_install_message:
174
183
  rdoc_options: []
175
184
  require_paths:
176
185
  - lib
177
186
  required_ruby_version: !ruby/object:Gem::Requirement
178
- none: false
179
187
  requirements:
180
- - - ! '>='
188
+ - - ">="
181
189
  - !ruby/object:Gem::Version
182
190
  version: '0'
183
191
  required_rubygems_version: !ruby/object:Gem::Requirement
184
- none: false
185
192
  requirements:
186
- - - ! '>='
193
+ - - ">="
187
194
  - !ruby/object:Gem::Version
188
195
  version: '0'
189
196
  requirements: []
190
- rubyforge_project:
191
- rubygems_version: 1.8.23.2
197
+ rubygems_version: 3.1.2
192
198
  signing_key:
193
- specification_version: 3
194
- summary: ! 'Einhorn: the language-independent shared socket manager'
199
+ specification_version: 4
200
+ summary: 'Einhorn: the language-independent shared socket manager'
195
201
  test_files:
196
202
  - test/_lib.rb
197
203
  - test/integration/_lib.rb
198
204
  - test/integration/_lib/fixtures/env_printer/env_printer.rb
199
205
  - test/integration/_lib/fixtures/exit_during_upgrade/exiting_server.rb
200
206
  - test/integration/_lib/fixtures/exit_during_upgrade/upgrade_reexec.rb
207
+ - test/integration/_lib/fixtures/pdeathsig_printer/pdeathsig_printer.rb
208
+ - test/integration/_lib/fixtures/signal_timeout/sleepy_server.rb
201
209
  - test/integration/_lib/fixtures/upgrade_project/upgrading_server.rb
202
210
  - test/integration/_lib/helpers.rb
203
211
  - test/integration/_lib/helpers/einhorn_helpers.rb
212
+ - test/integration/pdeathsig.rb
204
213
  - test/integration/startup.rb
205
214
  - test/integration/upgrading.rb
215
+ - test/unit/_lib/bad_worker.rb
216
+ - test/unit/_lib/sleep_worker.rb
206
217
  - test/unit/einhorn.rb
207
218
  - test/unit/einhorn/client.rb
208
219
  - test/unit/einhorn/command.rb
209
220
  - test/unit/einhorn/command/interface.rb
210
221
  - test/unit/einhorn/event.rb
211
222
  - test/unit/einhorn/worker_pool.rb
212
- has_rdoc: