theine 0.0.10.rc1 → 0.0.10
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.
- checksums.yaml +7 -0
- data/lib/theine/client.rb +8 -119
- data/lib/theine/server.rb +64 -15
- data/lib/theine/worker.rb +36 -93
- metadata +15 -19
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 44a70acdfb48ffa54a63ec3720c61082f30342d2
|
4
|
+
data.tar.gz: 3a3c2dd8947da2b1f637f4950c08ca5511dea769
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d57a7544fd0f61d71a851aba79decded6ef277652a1e3f779c914d32dcf1ea7f12f0f805650714b5f11b597dab272dacb59afea8e671a15028b86ce81ecb15d4
|
7
|
+
data.tar.gz: fe22098198bb33413f763bd98de9117c2754c6ad3b00ccc4ae7fca432e73e9d1d1159b9e49e4115af076d4aa32d4dbfc0d3a5a7416518ab7dcfd0e30890ac185
|
data/lib/theine/client.rb
CHANGED
@@ -2,79 +2,6 @@ require 'drb/drb'
|
|
2
2
|
require 'readline'
|
3
3
|
require_relative './config'
|
4
4
|
|
5
|
-
class IOUndumpedProxy
|
6
|
-
include DRb::DRbUndumped
|
7
|
-
|
8
|
-
def initialize(obj)
|
9
|
-
@obj = obj
|
10
|
-
create_method_proxies
|
11
|
-
end
|
12
|
-
|
13
|
-
def completion_proc=(val)
|
14
|
-
if @obj.respond_to? :completion_proc=
|
15
|
-
@obj.completion_proc = val
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def completion_proc
|
20
|
-
@obj.completion_proc if @obj.respond_to? :completion_proc
|
21
|
-
end
|
22
|
-
|
23
|
-
def readline(prompt)
|
24
|
-
if ::Readline == @obj
|
25
|
-
@obj.readline(prompt, true)
|
26
|
-
elsif @obj.method(:readline).arity == 1
|
27
|
-
@obj.readline(prompt)
|
28
|
-
else
|
29
|
-
$stdout.print prompt
|
30
|
-
@obj.readline
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def readline_arity
|
35
|
-
method(:readline).arity
|
36
|
-
rescue NameError
|
37
|
-
0
|
38
|
-
end
|
39
|
-
|
40
|
-
def <<(data)
|
41
|
-
@obj << data
|
42
|
-
self
|
43
|
-
end
|
44
|
-
|
45
|
-
# Some versions of Pry expect $stdout or its output objects to respond to
|
46
|
-
# this message.
|
47
|
-
def tty?
|
48
|
-
false
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
# http://www.ruby-doc.org/core-1.9.3/IO.html
|
53
|
-
# Creating method proxies. We take this approach so that method.arity will
|
54
|
-
# give the correct result (if we just used *args it would always return -1).
|
55
|
-
# Can't use SimpleDelegator, won't work over DRb
|
56
|
-
def create_method_proxies
|
57
|
-
(@obj.public_methods - public_methods).each do |meth|
|
58
|
-
next unless @obj.respond_to?(meth)
|
59
|
-
arity = @obj.method(meth).arity
|
60
|
-
if arity >= 0
|
61
|
-
args = arity.times.map { |i| "a#{i+1}" }
|
62
|
-
else
|
63
|
-
args = (arity.abs - 1).times.map { |i| "a#{i+1}" }
|
64
|
-
args << "*args"
|
65
|
-
args = args
|
66
|
-
end
|
67
|
-
args = (args + ["&block"]).join(", ")
|
68
|
-
|
69
|
-
singleton_class.class_eval <<-EOS
|
70
|
-
def #{meth}(#{args})
|
71
|
-
@obj.send(:#{meth}, #{args})
|
72
|
-
end
|
73
|
-
EOS
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
5
|
module Theine
|
79
6
|
class Client
|
80
7
|
def self.start
|
@@ -85,29 +12,20 @@ module Theine
|
|
85
12
|
|
86
13
|
def initialize
|
87
14
|
@config = ConfigReader.new(Dir.pwd)
|
88
|
-
|
89
|
-
trap_signals
|
15
|
+
@argv = ARGV.dup
|
90
16
|
begin
|
91
17
|
connect_worker
|
92
|
-
redirect_io
|
93
18
|
run_command
|
94
|
-
|
95
|
-
|
19
|
+
attach_screen
|
20
|
+
exit_prompt
|
96
21
|
end
|
97
22
|
end
|
98
23
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
%x[kill -2 #{@worker.pid}] # TODO: if client was term-ed, term worker (maybe term)
|
103
|
-
sleep(sleep_for) if sleep_for > 0 # to finish receiving IO
|
104
|
-
end
|
105
|
-
rescue DRb::DRbConnError
|
106
|
-
end
|
107
|
-
exit(0)
|
24
|
+
private
|
25
|
+
def attach_screen
|
26
|
+
exec("screen -r theine#{@port}")
|
108
27
|
end
|
109
28
|
|
110
|
-
private
|
111
29
|
def run_command
|
112
30
|
case @argv[0]
|
113
31
|
when "rake"
|
@@ -117,51 +35,22 @@ module Theine
|
|
117
35
|
@argv.shift
|
118
36
|
@worker.command_rspec(@argv)
|
119
37
|
else
|
120
|
-
if ["c", "console"].include?(@argv[0])
|
121
|
-
load_pry_history
|
122
|
-
end
|
123
38
|
@worker.command_rails(@argv)
|
124
39
|
end
|
125
40
|
rescue DRb::DRbConnError
|
126
41
|
$stderr.puts "\nTheine closed the connection."
|
127
42
|
end
|
128
43
|
|
129
|
-
def load_pry_history
|
130
|
-
history_file = File.expand_path("~/.pry_history")
|
131
|
-
if File.exist?(history_file)
|
132
|
-
File.readlines(history_file).pop(100).each do |line|
|
133
|
-
Readline::HISTORY << line[0, line.size-1]
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
def reset_argv!
|
139
|
-
@argv = ARGV.dup
|
140
|
-
ARGV.clear
|
141
|
-
end
|
142
|
-
|
143
|
-
def trap_signals
|
144
|
-
trap('INT') { exit(0) } # TODO: is this needed?
|
145
|
-
trap('TERM') { exit(0) }
|
146
|
-
end
|
147
|
-
|
148
|
-
def redirect_io
|
149
|
-
# Need to be careful that these don't get garbage collected
|
150
|
-
$stdin_undumped = @worker.stdin = IOUndumpedProxy.new(Readline)
|
151
|
-
$stdout_undumped = @worker.stdout = IOUndumpedProxy.new($stdout)
|
152
|
-
$stderr_undumped = @worker.stderr = IOUndumpedProxy.new($stderr)
|
153
|
-
end
|
154
|
-
|
155
44
|
def connect_worker
|
156
45
|
balancer = wait_until_result("Cannot connect to theine server. Waiting") do
|
157
46
|
object = DRbObject.new_with_uri("druby://localhost:#{config.base_port}")
|
158
47
|
object.respond_to?(:get_port) # test if connected
|
159
48
|
object
|
160
49
|
end
|
161
|
-
port = wait_until_result("Waiting for Theine worker...") do
|
50
|
+
@port = wait_until_result("Waiting for Theine worker...") do
|
162
51
|
balancer.get_port
|
163
52
|
end
|
164
|
-
@worker = DRbObject.new_with_uri("druby://localhost:#{port}")
|
53
|
+
@worker = DRbObject.new_with_uri("druby://localhost:#{@port}")
|
165
54
|
end
|
166
55
|
|
167
56
|
WaitResultNoResultError = Class.new(StandardError)
|
data/lib/theine/server.rb
CHANGED
@@ -12,7 +12,9 @@ module Theine
|
|
12
12
|
@config = ConfigReader.new(Dir.pwd)
|
13
13
|
|
14
14
|
@workers = []
|
15
|
-
@
|
15
|
+
@workers_in_use = []
|
16
|
+
@worker_pids = {}
|
17
|
+
@spawning_workers = []
|
16
18
|
|
17
19
|
@available_ports = ((config.base_port + 1)..config.max_port).to_a
|
18
20
|
@check_mutex = Mutex.new
|
@@ -23,33 +25,48 @@ module Theine
|
|
23
25
|
|
24
26
|
def add_worker
|
25
27
|
path = File.expand_path('../worker.rb', __FILE__)
|
26
|
-
port = @available_ports.shift
|
28
|
+
port = @workers_mutex.synchronize { @available_ports.shift }
|
27
29
|
puts "(spawn #{port})"
|
28
|
-
spawn("
|
29
|
-
|
30
|
+
spawn("screen", "-d", "-m", "-S", worker_session_name(port),
|
31
|
+
"sh", "-c",
|
32
|
+
"ruby #{path} #{config.base_port.to_s} #{port.to_s} #{config.rails_root}; read -p 'Press [Enter] to exit...\n'")
|
33
|
+
@workers_mutex.synchronize { @spawning_workers << port }
|
34
|
+
end
|
35
|
+
|
36
|
+
def worker_session_name(port)
|
37
|
+
"theine#{port}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def set_worker_pid(port, pid)
|
41
|
+
@workers_mutex.synchronize do
|
42
|
+
@worker_pids[port] = pid
|
43
|
+
end
|
30
44
|
end
|
31
45
|
|
32
46
|
def worker_boot(port)
|
33
47
|
puts "+ worker #{port}"
|
34
48
|
|
35
49
|
@workers_mutex.synchronize do
|
36
|
-
@
|
50
|
+
@spawning_workers.delete(port)
|
37
51
|
@workers << port
|
38
52
|
end
|
39
53
|
end
|
40
54
|
|
41
55
|
def worker_done(port)
|
42
56
|
puts "- worker #{port}"
|
57
|
+
@workers_mutex.synchronize do
|
58
|
+
@workers_in_use.delete(port)
|
59
|
+
@available_ports << port
|
60
|
+
end
|
43
61
|
end
|
44
62
|
|
45
|
-
def get_port
|
46
|
-
add_worker if all_size == 0
|
63
|
+
def get_port(spawn_new = true)
|
64
|
+
add_worker if spawn_new && all_size == 0
|
47
65
|
|
48
|
-
port = @workers_mutex.synchronize
|
49
|
-
|
50
|
-
end
|
66
|
+
port = @workers_mutex.synchronize { @workers.shift }
|
67
|
+
@workers_mutex.synchronize { @workers_in_use << port } if port
|
51
68
|
|
52
|
-
Thread.new { check_min_free_workers }
|
69
|
+
Thread.new { check_min_free_workers } if spawn_new
|
53
70
|
|
54
71
|
port
|
55
72
|
end
|
@@ -60,7 +77,7 @@ module Theine
|
|
60
77
|
# do this in thread
|
61
78
|
while all_size < config.min_free_workers
|
62
79
|
unless config.spawn_parallel
|
63
|
-
sleep 0.1 until @workers_mutex.synchronize { @
|
80
|
+
sleep 0.1 until @workers_mutex.synchronize { @spawning_workers.empty? }
|
64
81
|
end
|
65
82
|
add_worker
|
66
83
|
end
|
@@ -69,10 +86,43 @@ module Theine
|
|
69
86
|
end
|
70
87
|
|
71
88
|
def all_size
|
72
|
-
@workers_mutex.synchronize { @workers.size + @
|
89
|
+
@workers_mutex.synchronize { @workers.size + @spawning_workers.size }
|
90
|
+
end
|
91
|
+
|
92
|
+
def stop!
|
93
|
+
if spawning_worker_pids.include?(nil)
|
94
|
+
puts "Waiting for workers to quit..."
|
95
|
+
sleep 0.1 while spawning_worker_pids.include?(nil)
|
96
|
+
end
|
97
|
+
|
98
|
+
@workers_mutex.synchronize do
|
99
|
+
(@spawning_workers + @workers_in_use + @workers).each do |port|
|
100
|
+
kill_worker(port)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
exit(0)
|
73
104
|
end
|
74
105
|
private
|
106
|
+
def kill_worker(port)
|
107
|
+
print "- worker #{port}"
|
108
|
+
worker_pid = @worker_pids[port]
|
109
|
+
worker_pid ||= DRbObject.new_with_uri("druby://localhost:#{port}").pid
|
110
|
+
system("kill -9 #{worker_pid} > /dev/null 2>&1")
|
111
|
+
session_name = worker_session_name(port)
|
112
|
+
system("screen -S #{session_name} -X quit > /dev/null 2>&1")
|
113
|
+
puts "."
|
114
|
+
rescue
|
115
|
+
end
|
116
|
+
|
117
|
+
def spawning_worker_pids
|
118
|
+
@spawning_workers.map { |port| @worker_pids[port] }
|
119
|
+
end
|
120
|
+
|
75
121
|
def run
|
122
|
+
trap("INT") { stop! }
|
123
|
+
trap("TERM") { stop! }
|
124
|
+
system("screen -wipe > /dev/null 2>&1")
|
125
|
+
|
76
126
|
DRb.start_service("druby://localhost:#{config.base_port}", self)
|
77
127
|
check_min_free_workers
|
78
128
|
DRb.thread.join
|
@@ -80,5 +130,4 @@ module Theine
|
|
80
130
|
end
|
81
131
|
end
|
82
132
|
|
83
|
-
|
84
|
-
|
133
|
+
Theine::Server.new
|
data/lib/theine/worker.rb
CHANGED
@@ -1,139 +1,82 @@
|
|
1
|
-
|
2
|
-
APP_PATH = "#{
|
3
|
-
require "#{root_path}/config/boot"
|
4
|
-
require "#{root_path}/config/environment"
|
1
|
+
RAILS_ROOT_PATH = ARGV[2]
|
2
|
+
APP_PATH = "#{RAILS_ROOT_PATH}/config/application"
|
5
3
|
require 'drb/drb'
|
6
|
-
require 'delegate'
|
7
|
-
|
8
|
-
$real_stdout = $stdout
|
9
|
-
$real_stderr = $stderr
|
10
4
|
|
11
5
|
module Theine
|
12
|
-
class InputProxy < SimpleDelegator
|
13
|
-
# Reads a line from the input
|
14
|
-
def readline(prompt)
|
15
|
-
case readline_arity
|
16
|
-
when 1 then __getobj__.readline(prompt)
|
17
|
-
else __getobj__.readline
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
6
|
class Worker
|
23
|
-
attr_reader :
|
7
|
+
attr_reader :command_proc
|
24
8
|
|
25
9
|
def initialize
|
26
10
|
@pumps = []
|
11
|
+
@command_proc = proc { }
|
27
12
|
end
|
28
13
|
|
29
|
-
def
|
30
|
-
|
14
|
+
def boot
|
15
|
+
require "#{RAILS_ROOT_PATH}/config/boot"
|
16
|
+
require "#{RAILS_ROOT_PATH}/config/environment"
|
17
|
+
end
|
31
18
|
|
19
|
+
def command_rails(argv)
|
32
20
|
ARGV.clear
|
33
21
|
ARGV.concat(argv)
|
34
22
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
require 'rails/commands'
|
40
|
-
sleep 0.1 # allow Pumps to finish
|
41
|
-
DRb.stop_service
|
23
|
+
set_command do
|
24
|
+
require 'rails/commands'
|
25
|
+
end
|
42
26
|
end
|
43
27
|
|
44
28
|
def command_rake(argv)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
29
|
+
set_command do
|
30
|
+
::Rails.application.load_tasks
|
31
|
+
argv.each do |task|
|
32
|
+
::Rake::Task[task].invoke
|
33
|
+
end
|
49
34
|
end
|
50
35
|
end
|
51
36
|
|
52
37
|
def command_rspec(argv)
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
def pry_setup
|
59
|
-
::Pry.config.input = stdin
|
60
|
-
::Pry.config.output = stdout
|
61
|
-
end
|
62
|
-
|
63
|
-
def stdin=(value)
|
64
|
-
@stdin = InputProxy.new(value)
|
65
|
-
$stdin = @stdin
|
66
|
-
end
|
67
|
-
|
68
|
-
def stdout=(value)
|
69
|
-
patch_out_io($stdout, value)
|
70
|
-
@stdout = value
|
71
|
-
r, w = IO.pipe
|
72
|
-
$stdout = w
|
73
|
-
@pumps << Pump.new(r, @stdout)
|
74
|
-
end
|
75
|
-
|
76
|
-
def stderr=(value)
|
77
|
-
patch_out_io($stderr, value)
|
78
|
-
@stderr = value
|
79
|
-
r, w = IO.pipe
|
80
|
-
$stderr = w
|
81
|
-
@pumps << Pump.new(r, @stderr)
|
38
|
+
set_command do
|
39
|
+
require 'rspec/core'
|
40
|
+
::RSpec::Core::Runner.run(argv, $stderr, $stdout)
|
41
|
+
end
|
82
42
|
end
|
83
43
|
|
84
44
|
def pid
|
85
45
|
::Process.pid
|
86
46
|
end
|
87
47
|
|
48
|
+
def stop!
|
49
|
+
exit(1)
|
50
|
+
end
|
88
51
|
private
|
89
|
-
def
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
# $stdout to, so this is why we patch it here.
|
94
|
-
io.singleton_class.send :define_method, :write do |*args, &block|
|
95
|
-
write_to.write(*args, &block)
|
96
|
-
end
|
52
|
+
def set_command(&block)
|
53
|
+
rails_reload!
|
54
|
+
@command_proc = block
|
55
|
+
DRb.stop_service
|
97
56
|
end
|
98
57
|
|
99
58
|
def rails_reload!
|
100
59
|
ActionDispatch::Reloader.cleanup!
|
101
60
|
ActionDispatch::Reloader.prepare!
|
102
61
|
end
|
103
|
-
|
104
|
-
class Pump < Thread
|
105
|
-
def initialize(input, output)
|
106
|
-
if output
|
107
|
-
@input = input
|
108
|
-
@output = output
|
109
|
-
super(&method(:main))
|
110
|
-
else
|
111
|
-
close_stream(input)
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
private
|
116
|
-
def main
|
117
|
-
while buf = @input.sysread(1024)
|
118
|
-
@output.print(buf)
|
119
|
-
@output.flush
|
120
|
-
end
|
121
|
-
ensure
|
122
|
-
@output.close
|
123
|
-
end
|
124
|
-
end
|
125
62
|
end
|
126
63
|
end
|
127
64
|
|
128
65
|
base_port = ARGV[0]
|
129
|
-
worker_port = ARGV[1]
|
130
|
-
|
66
|
+
worker_port = ARGV[1].to_i
|
67
|
+
|
68
|
+
worker = Theine::Worker.new
|
131
69
|
|
132
70
|
balancer = DRbObject.new_with_uri("druby://localhost:#{base_port}")
|
71
|
+
balancer.set_worker_pid(worker_port, worker.pid)
|
72
|
+
|
73
|
+
worker.boot
|
74
|
+
DRb.start_service("druby://localhost:#{worker_port}", worker)
|
133
75
|
balancer.worker_boot(worker_port)
|
134
76
|
|
135
77
|
begin
|
136
78
|
DRb.thread.join
|
79
|
+
worker.command_proc.call
|
137
80
|
ensure
|
138
81
|
balancer.worker_done(worker_port)
|
139
82
|
end
|
metadata
CHANGED
@@ -1,32 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: theine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
version: 0.0.10.rc1
|
4
|
+
version: 0.0.10
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Jan Berdajs
|
9
|
-
autorequire:
|
8
|
+
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-10-
|
11
|
+
date: 2013-10-20 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: pry
|
16
|
-
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
17
16
|
requirements:
|
18
17
|
- - '>='
|
19
18
|
- !ruby/object:Gem::Version
|
20
19
|
version: '0'
|
21
|
-
|
22
|
-
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
none: false
|
28
|
-
prerelease: false
|
29
|
-
type: :runtime
|
30
27
|
description: A Rails preloader for JRuby
|
31
28
|
email: mrbrdo@mrbrdo.net
|
32
29
|
executables:
|
@@ -49,7 +46,8 @@ files:
|
|
49
46
|
homepage: https://github.com/mrbrdo/theine
|
50
47
|
licenses:
|
51
48
|
- MIT
|
52
|
-
|
49
|
+
metadata: {}
|
50
|
+
post_install_message:
|
53
51
|
rdoc_options: []
|
54
52
|
require_paths:
|
55
53
|
- lib
|
@@ -58,17 +56,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
58
56
|
- - '>='
|
59
57
|
- !ruby/object:Gem::Version
|
60
58
|
version: '0'
|
61
|
-
none: false
|
62
59
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
60
|
requirements:
|
64
|
-
- - '
|
61
|
+
- - '>='
|
65
62
|
- !ruby/object:Gem::Version
|
66
|
-
version:
|
67
|
-
none: false
|
63
|
+
version: '0'
|
68
64
|
requirements: []
|
69
|
-
rubyforge_project:
|
70
|
-
rubygems_version:
|
71
|
-
signing_key:
|
72
|
-
specification_version:
|
65
|
+
rubyforge_project:
|
66
|
+
rubygems_version: 2.0.6
|
67
|
+
signing_key:
|
68
|
+
specification_version: 4
|
73
69
|
summary: Theine
|
74
70
|
test_files: []
|