einhorn 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CONTRIBUTORS +6 -0
- data/Gemfile +5 -1
- data/Rakefile +12 -0
- data/bin/einhornsh +42 -13
- data/einhorn.gemspec +12 -8
- data/lib/einhorn/command.rb +3 -2
- data/lib/einhorn/version.rb +1 -1
- data/lib/einhorn/worker_pool.rb +16 -0
- metadata +69 -4
data/CONTRIBUTORS
ADDED
data/Gemfile
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
-
|
1
|
+
# Execute bundler hook if present
|
2
|
+
['~/.', '/etc/'].any? do |file|
|
3
|
+
File.lstat(path = File.expand_path(file + 'bundle-gemfile-hook')) rescue next
|
4
|
+
eval(File.read(path), binding, path); break true
|
5
|
+
end || source('https://rubygems.org/')
|
2
6
|
|
3
7
|
# Specify your gem's dependencies in einhorn.gemspec
|
4
8
|
gemspec
|
data/Rakefile
CHANGED
@@ -20,3 +20,15 @@ end
|
|
20
20
|
|
21
21
|
task :default => :test do
|
22
22
|
end
|
23
|
+
require 'bundler/setup'
|
24
|
+
require 'chalk-rake/gem_tasks'
|
25
|
+
require 'rake/testtask'
|
26
|
+
|
27
|
+
Rake::TestTask.new do |t|
|
28
|
+
t.libs = ['lib']
|
29
|
+
# t.warning = true
|
30
|
+
t.verbose = true
|
31
|
+
t.test_files = FileList['test/**/*.rb'].reject do |file|
|
32
|
+
file.end_with?('_lib.rb') || file.include?('/_lib/')
|
33
|
+
end
|
34
|
+
end
|
data/bin/einhornsh
CHANGED
@@ -11,6 +11,9 @@ require 'einhorn'
|
|
11
11
|
module Einhorn
|
12
12
|
class EinhornSH
|
13
13
|
|
14
|
+
class EinhornSHExit < StandardError
|
15
|
+
end
|
16
|
+
|
14
17
|
def initialize(path_to_socket)
|
15
18
|
@path_to_socket = path_to_socket
|
16
19
|
@request_id = 0
|
@@ -42,15 +45,28 @@ module Einhorn
|
|
42
45
|
emit
|
43
46
|
emit('Type "quit" or "exit" to quit at any time')
|
44
47
|
|
45
|
-
while
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
48
|
+
while command_line_sequence = Readline.readline('> ', true)
|
49
|
+
run_command_line_sequence(command_line_sequence)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def run_command_line_sequence(command_line_sequence)
|
54
|
+
command_lines = command_line_sequence.split(";")
|
55
|
+
command_lines.each do |command_line|
|
56
|
+
run_command_line(command_line)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def run_command_line(command_line)
|
61
|
+
command, args = parse_command_line(command_line)
|
62
|
+
if command.nil?
|
63
|
+
return
|
64
|
+
elsif ['quit', 'exit'].include?(command)
|
65
|
+
emit("Goodbye!")
|
66
|
+
raise EinhornSHExit
|
67
|
+
end
|
68
|
+
send_command({'id' => request_id, 'command' => command, 'args' => args}) do |message|
|
69
|
+
puts message
|
54
70
|
end
|
55
71
|
end
|
56
72
|
|
@@ -58,8 +74,8 @@ module Einhorn
|
|
58
74
|
@request_id += 1
|
59
75
|
end
|
60
76
|
|
61
|
-
def
|
62
|
-
command, *args = Shellwords.shellsplit(
|
77
|
+
def parse_command_line(command_line)
|
78
|
+
command, *args = Shellwords.shellsplit(command_line)
|
63
79
|
[command, args]
|
64
80
|
end
|
65
81
|
|
@@ -128,6 +144,11 @@ with a `-d`, provide the same argument here."
|
|
128
144
|
opts.on('-d PATH', '--socket-path PATH', 'Path to the Einhorn command socket') do |path|
|
129
145
|
options[:socket_path] = path
|
130
146
|
end
|
147
|
+
|
148
|
+
opts.on('-e CMD_LINE_SEQ', '--execute CMD_LINE_SEQ', 'Execute this command outside of interactive mode') do |cmd_line_seq|
|
149
|
+
options[:cmd_line_seq] = cmd_line_seq
|
150
|
+
end
|
151
|
+
|
131
152
|
end
|
132
153
|
optparse.parse!
|
133
154
|
|
@@ -148,8 +169,16 @@ with a `-d`, provide the same argument here."
|
|
148
169
|
path_to_socket = Einhorn::Command::Interface.default_socket_path(cmd_name)
|
149
170
|
end
|
150
171
|
|
151
|
-
sh = Einhorn::EinhornSH.new(path_to_socket)
|
152
|
-
|
172
|
+
sh = Einhorn::EinhornSH.new(path_to_socket)
|
173
|
+
|
174
|
+
cmd_line_seq = options[:cmd_line_seq]
|
175
|
+
|
176
|
+
begin
|
177
|
+
cmd_line_seq ? sh.run_command_line_sequence(cmd_line_seq) : sh.run
|
178
|
+
rescue Einhorn::EinhornSH::EinhornSHExit => e
|
179
|
+
return 0
|
180
|
+
end
|
181
|
+
|
153
182
|
return 0
|
154
183
|
end
|
155
184
|
|
data/einhorn.gemspec
CHANGED
@@ -2,18 +2,22 @@
|
|
2
2
|
require File.expand_path('../lib/einhorn/version', __FILE__)
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
|
-
gem.authors = [
|
6
|
-
gem.email = [
|
7
|
-
gem.summary =
|
8
|
-
gem.description =
|
9
|
-
gem.homepage =
|
10
|
-
gem.license =
|
5
|
+
gem.authors = ['Greg Brockman']
|
6
|
+
gem.email = ['gdb@stripe.com']
|
7
|
+
gem.summary = 'Einhorn: the language-independent shared socket manager'
|
8
|
+
gem.description = 'Einhorn makes it easy to run multiple instances of an application server, all listening on the same port. You can also seamlessly restart your workers without dropping any requests. Einhorn requires minimal application-level support, making it easy to use with an existing project.'
|
9
|
+
gem.homepage = 'https://github.com/stripe/einhorn'
|
10
|
+
gem.license = 'MIT'
|
11
11
|
|
12
12
|
gem.files = `git ls-files`.split($\)
|
13
13
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
14
14
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
|
-
gem.name =
|
16
|
-
gem.require_paths = [
|
15
|
+
gem.name = 'einhorn'
|
16
|
+
gem.require_paths = ['lib']
|
17
|
+
gem.add_development_dependency 'rake'
|
18
|
+
gem.add_development_dependency 'minitest'
|
19
|
+
gem.add_development_dependency 'mocha'
|
20
|
+
gem.add_development_dependency 'chalk-rake'
|
17
21
|
|
18
22
|
gem.add_development_dependency('rake')
|
19
23
|
gem.add_development_dependency('minitest', '< 5.0')
|
data/lib/einhorn/command.rb
CHANGED
@@ -319,6 +319,7 @@ module Einhorn
|
|
319
319
|
|
320
320
|
def self.cull
|
321
321
|
acked = Einhorn::WorkerPool.ack_count
|
322
|
+
unsignaled = Einhorn::WorkerPool.unsignaled_count
|
322
323
|
target = Einhorn::WorkerPool.ack_target
|
323
324
|
|
324
325
|
if Einhorn::State.upgrading && acked >= target
|
@@ -333,8 +334,8 @@ module Einhorn
|
|
333
334
|
signal_all("USR2", old_workers)
|
334
335
|
end
|
335
336
|
|
336
|
-
if
|
337
|
-
excess = Einhorn::WorkerPool.
|
337
|
+
if unsignaled > target
|
338
|
+
excess = Einhorn::WorkerPool.unsignaled_modern_workers_with_priority[0...(unsignaled-target)]
|
338
339
|
Einhorn.log_info("Have too many workers at the current version, so killing off #{excess.length} of them.")
|
339
340
|
signal_all("USR2", excess)
|
340
341
|
end
|
data/lib/einhorn/version.rb
CHANGED
data/lib/einhorn/worker_pool.rb
CHANGED
@@ -34,12 +34,24 @@ module Einhorn
|
|
34
34
|
acked_modern_workers_with_state.map {|pid, _| pid}
|
35
35
|
end
|
36
36
|
|
37
|
+
def self.unsignaled_modern_workers_with_state
|
38
|
+
modern_workers_with_state.select do |_, spec|
|
39
|
+
spec[:signaled].length == 0
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
37
43
|
def self.acked_unsignaled_modern_workers
|
38
44
|
acked_modern_workers_with_state.select do |_, spec|
|
39
45
|
spec[:signaled].length == 0
|
40
46
|
end.map {|pid, _| pid}
|
41
47
|
end
|
42
48
|
|
49
|
+
def self.unsignaled_modern_workers_with_priority
|
50
|
+
unsignaled_modern_workers_with_state.sort_by do |pid, spec|
|
51
|
+
spec[:acked] ? 1 : 0
|
52
|
+
end.map {|pid, _| pid}
|
53
|
+
end
|
54
|
+
|
43
55
|
# Use the number of modern workers, rather than unsignaled modern
|
44
56
|
# workers. This means if e.g. we do bunch of decs and then incs,
|
45
57
|
# any workers which haven't died yet will count towards our number
|
@@ -59,6 +71,10 @@ module Einhorn
|
|
59
71
|
Einhorn::State.config[:number]
|
60
72
|
end
|
61
73
|
|
74
|
+
def self.unsignaled_count
|
75
|
+
unsignaled_modern_workers_with_state.length
|
76
|
+
end
|
77
|
+
|
62
78
|
def self.old_workers
|
63
79
|
unsignaled_workers - modern_workers
|
64
80
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: einhorn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,72 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-10-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: minitest
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: mocha
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: chalk-rake
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
14
78
|
- !ruby/object:Gem::Dependency
|
15
79
|
name: rake
|
16
80
|
requirement: !ruby/object:Gem::Requirement
|
@@ -73,6 +137,7 @@ extra_rdoc_files: []
|
|
73
137
|
files:
|
74
138
|
- .gitignore
|
75
139
|
- .travis.yml
|
140
|
+
- CONTRIBUTORS
|
76
141
|
- Gemfile
|
77
142
|
- History.txt
|
78
143
|
- LICENSE
|
@@ -132,7 +197,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
132
197
|
version: '0'
|
133
198
|
segments:
|
134
199
|
- 0
|
135
|
-
hash:
|
200
|
+
hash: -4058700174817085581
|
136
201
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
202
|
none: false
|
138
203
|
requirements:
|
@@ -141,7 +206,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
206
|
version: '0'
|
142
207
|
segments:
|
143
208
|
- 0
|
144
|
-
hash:
|
209
|
+
hash: -4058700174817085581
|
145
210
|
requirements: []
|
146
211
|
rubyforge_project:
|
147
212
|
rubygems_version: 1.8.23
|