spring-jruby 1.4.3
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/LICENSE.txt +22 -0
- data/README.md +364 -0
- data/bin/spring +49 -0
- data/lib/spring-jruby/application.rb +283 -0
- data/lib/spring-jruby/application/boot.rb +19 -0
- data/lib/spring-jruby/binstub.rb +13 -0
- data/lib/spring-jruby/boot.rb +9 -0
- data/lib/spring-jruby/client.rb +46 -0
- data/lib/spring-jruby/client/binstub.rb +188 -0
- data/lib/spring-jruby/client/command.rb +18 -0
- data/lib/spring-jruby/client/help.rb +62 -0
- data/lib/spring-jruby/client/rails.rb +34 -0
- data/lib/spring-jruby/client/run.rb +167 -0
- data/lib/spring-jruby/client/status.rb +30 -0
- data/lib/spring-jruby/client/stop.rb +22 -0
- data/lib/spring-jruby/client/version.rb +11 -0
- data/lib/spring-jruby/command_wrapper.rb +82 -0
- data/lib/spring-jruby/commands.rb +51 -0
- data/lib/spring-jruby/commands/rails.rb +112 -0
- data/lib/spring-jruby/commands/rake.rb +30 -0
- data/lib/spring-jruby/configuration.rb +60 -0
- data/lib/spring-jruby/env.rb +109 -0
- data/lib/spring-jruby/errors.rb +36 -0
- data/lib/spring-jruby/impl/application.rb +7 -0
- data/lib/spring-jruby/impl/application_manager.rb +7 -0
- data/lib/spring-jruby/impl/fork/application.rb +69 -0
- data/lib/spring-jruby/impl/fork/application_manager.rb +137 -0
- data/lib/spring-jruby/impl/fork/run.rb +47 -0
- data/lib/spring-jruby/impl/pool/application.rb +47 -0
- data/lib/spring-jruby/impl/pool/application_manager.rb +226 -0
- data/lib/spring-jruby/impl/pool/run.rb +27 -0
- data/lib/spring-jruby/impl/run.rb +7 -0
- data/lib/spring-jruby/io_helpers.rb +92 -0
- data/lib/spring-jruby/json.rb +626 -0
- data/lib/spring-jruby/platform.rb +23 -0
- data/lib/spring-jruby/process_title_updater.rb +65 -0
- data/lib/spring-jruby/server.rb +130 -0
- data/lib/spring-jruby/sid.rb +42 -0
- data/lib/spring-jruby/test.rb +18 -0
- data/lib/spring-jruby/test/acceptance_test.rb +371 -0
- data/lib/spring-jruby/test/application.rb +217 -0
- data/lib/spring-jruby/test/application_generator.rb +134 -0
- data/lib/spring-jruby/test/rails_version.rb +40 -0
- data/lib/spring-jruby/test/watcher_test.rb +167 -0
- data/lib/spring-jruby/version.rb +3 -0
- data/lib/spring-jruby/watcher.rb +30 -0
- data/lib/spring-jruby/watcher/abstract.rb +86 -0
- data/lib/spring-jruby/watcher/polling.rb +61 -0
- metadata +137 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
module Spring
|
2
|
+
class ClientError < StandardError; end
|
3
|
+
|
4
|
+
class UnknownProject < StandardError
|
5
|
+
attr_reader :current_dir
|
6
|
+
|
7
|
+
def initialize(current_dir)
|
8
|
+
@current_dir = current_dir
|
9
|
+
end
|
10
|
+
|
11
|
+
def message
|
12
|
+
"Spring was unable to locate the root of your project. There was no Gemfile " \
|
13
|
+
"present in the current directory (#{current_dir}) or any of the parent " \
|
14
|
+
"directories."
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class MissingApplication < ClientError
|
19
|
+
attr_reader :project_root
|
20
|
+
|
21
|
+
def initialize(project_root)
|
22
|
+
@project_root = project_root
|
23
|
+
end
|
24
|
+
|
25
|
+
def message
|
26
|
+
"Spring was unable to find your config/application.rb file. " \
|
27
|
+
"Your project root was detected at #{project_root}, so spring " \
|
28
|
+
"looked for #{project_root}/config/application.rb but it doesn't exist. You can " \
|
29
|
+
"configure the root of your application by setting Spring.application_root in " \
|
30
|
+
"config/spring.rb."
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class CommandNotFound < ClientError
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Spring
|
2
|
+
module ApplicationImpl
|
3
|
+
def notify_manager_ready
|
4
|
+
manager.puts
|
5
|
+
end
|
6
|
+
|
7
|
+
def receive_streams(client)
|
8
|
+
3.times.map { IOWrapper.recv_io(client).to_io }
|
9
|
+
end
|
10
|
+
|
11
|
+
def reopen_streams(streams)
|
12
|
+
[STDOUT, STDERR, STDIN].zip(streams).each { |a, b| a.reopen(b) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def eager_preload
|
16
|
+
with_pty { preload }
|
17
|
+
end
|
18
|
+
|
19
|
+
def with_pty
|
20
|
+
PTY.open do |master, slave|
|
21
|
+
[STDOUT, STDERR, STDIN].each { |s| s.reopen slave }
|
22
|
+
Thread.new { master.read }
|
23
|
+
yield
|
24
|
+
reset_streams
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def reset_streams
|
29
|
+
[STDOUT, STDERR].each { |stream| stream.reopen(spring_env.log_file) }
|
30
|
+
STDIN.reopen("/dev/null")
|
31
|
+
end
|
32
|
+
|
33
|
+
def wait(pid, streams, client)
|
34
|
+
@mutex.synchronize { @waiting << pid }
|
35
|
+
|
36
|
+
# Wait in a separate thread so we can run multiple commands at once
|
37
|
+
Thread.new {
|
38
|
+
begin
|
39
|
+
_, status = Process.wait2 pid
|
40
|
+
log "#{pid} exited with #{status.exitstatus}"
|
41
|
+
|
42
|
+
streams.each(&:close)
|
43
|
+
client.puts(status.exitstatus)
|
44
|
+
client.close
|
45
|
+
ensure
|
46
|
+
@mutex.synchronize { @waiting.delete pid }
|
47
|
+
exit_if_finished
|
48
|
+
end
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
def fork_child(client, streams, child_started)
|
53
|
+
pid = fork { yield }
|
54
|
+
child_started[0] = true
|
55
|
+
|
56
|
+
disconnect_database
|
57
|
+
reset_streams
|
58
|
+
|
59
|
+
log "forked #{pid}"
|
60
|
+
manager.puts pid
|
61
|
+
|
62
|
+
wait pid, streams, client
|
63
|
+
end
|
64
|
+
|
65
|
+
def before_command
|
66
|
+
# NOP
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
module Spring
|
2
|
+
class ApplicationManager
|
3
|
+
attr_reader :pid, :child, :app_env, :spring_env, :status
|
4
|
+
|
5
|
+
def initialize(app_env)
|
6
|
+
@app_env = app_env
|
7
|
+
@spring_env = Env.new
|
8
|
+
@mutex = Mutex.new
|
9
|
+
@state = :running
|
10
|
+
end
|
11
|
+
|
12
|
+
def log(message)
|
13
|
+
spring_env.log "[application_manager:#{app_env}] #{message}"
|
14
|
+
end
|
15
|
+
|
16
|
+
# We're not using @mutex.synchronize to avoid the weird "<internal:prelude>:10"
|
17
|
+
# line which messes with backtraces in e.g. rspec
|
18
|
+
def synchronize
|
19
|
+
@mutex.lock
|
20
|
+
yield
|
21
|
+
ensure
|
22
|
+
@mutex.unlock
|
23
|
+
end
|
24
|
+
|
25
|
+
def start
|
26
|
+
start_child
|
27
|
+
end
|
28
|
+
|
29
|
+
def restart
|
30
|
+
return if @state == :stopping
|
31
|
+
start_child(true)
|
32
|
+
end
|
33
|
+
|
34
|
+
def alive?
|
35
|
+
@pid
|
36
|
+
end
|
37
|
+
|
38
|
+
def with_child
|
39
|
+
synchronize do
|
40
|
+
if alive?
|
41
|
+
begin
|
42
|
+
yield
|
43
|
+
rescue Errno::ECONNRESET, Errno::EPIPE
|
44
|
+
# The child has died but has not been collected by the wait thread yet,
|
45
|
+
# so start a new child and try again.
|
46
|
+
log "child dead; starting"
|
47
|
+
start
|
48
|
+
yield
|
49
|
+
end
|
50
|
+
else
|
51
|
+
log "child not running; starting"
|
52
|
+
start
|
53
|
+
yield
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns the pid of the process running the command, or nil if the application process died.
|
59
|
+
def run(client)
|
60
|
+
with_child do
|
61
|
+
child.send_io client
|
62
|
+
child.gets or raise Errno::EPIPE
|
63
|
+
end
|
64
|
+
|
65
|
+
pid = child.gets.to_i
|
66
|
+
|
67
|
+
unless pid.zero?
|
68
|
+
log "got worker pid #{pid}"
|
69
|
+
pid
|
70
|
+
end
|
71
|
+
rescue Errno::ECONNRESET, Errno::EPIPE => e
|
72
|
+
log "#{e} while reading from child; returning no pid"
|
73
|
+
nil
|
74
|
+
ensure
|
75
|
+
client.close
|
76
|
+
end
|
77
|
+
|
78
|
+
def stop
|
79
|
+
log "stopping"
|
80
|
+
@state = :stopping
|
81
|
+
|
82
|
+
if pid
|
83
|
+
Process.kill('TERM', pid)
|
84
|
+
Process.wait(pid)
|
85
|
+
end
|
86
|
+
rescue Errno::ESRCH, Errno::ECHILD
|
87
|
+
# Don't care
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def start_child(preload = false)
|
93
|
+
@child, child_socket = UNIXSocket.pair
|
94
|
+
|
95
|
+
Bundler.with_clean_env do
|
96
|
+
@pid = Process.spawn(
|
97
|
+
{
|
98
|
+
"RAILS_ENV" => app_env,
|
99
|
+
"RACK_ENV" => app_env,
|
100
|
+
"SPRING_ORIGINAL_ENV" => JSON.dump(Spring::ORIGINAL_ENV),
|
101
|
+
"SPRING_PRELOAD" => preload ? "1" : "0"
|
102
|
+
},
|
103
|
+
"ruby",
|
104
|
+
"-I", File.expand_path("../..", __FILE__),
|
105
|
+
"-e", "require 'spring-jruby/application/boot'",
|
106
|
+
3 => child_socket
|
107
|
+
)
|
108
|
+
end
|
109
|
+
|
110
|
+
start_wait_thread(pid, child) if child.gets
|
111
|
+
child_socket.close
|
112
|
+
end
|
113
|
+
|
114
|
+
def start_wait_thread(pid, child)
|
115
|
+
Process.detach(pid)
|
116
|
+
|
117
|
+
Thread.new {
|
118
|
+
# The recv can raise an ECONNRESET, killing the thread, but that's ok
|
119
|
+
# as if it does we're no longer interested in the child
|
120
|
+
loop do
|
121
|
+
IO.select([child])
|
122
|
+
break if child.recv(1, Socket::MSG_PEEK).empty?
|
123
|
+
sleep 0.01
|
124
|
+
end
|
125
|
+
|
126
|
+
log "child #{pid} shutdown"
|
127
|
+
|
128
|
+
synchronize {
|
129
|
+
if @pid == pid
|
130
|
+
@pid = nil
|
131
|
+
restart
|
132
|
+
end
|
133
|
+
}
|
134
|
+
}
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Spring
|
2
|
+
module Client
|
3
|
+
module RunImpl
|
4
|
+
TIMEOUT = 1
|
5
|
+
FORWARDED_SIGNALS = %w(INT QUIT USR1 USR2 INFO) & Signal.list.keys
|
6
|
+
|
7
|
+
def queue_signals
|
8
|
+
RunImpl::FORWARDED_SIGNALS.each do |sig|
|
9
|
+
trap(sig) { @signal_queue << sig }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def send_std_io_to(application)
|
14
|
+
application.send_io STDOUT
|
15
|
+
application.send_io STDERR
|
16
|
+
application.send_io STDIN
|
17
|
+
end
|
18
|
+
|
19
|
+
def run_on(application, pid)
|
20
|
+
forward_signals(pid.to_i)
|
21
|
+
status = application.read.to_i
|
22
|
+
|
23
|
+
log "got exit status #{status}"
|
24
|
+
|
25
|
+
exit status
|
26
|
+
end
|
27
|
+
|
28
|
+
def forward_signals(pid)
|
29
|
+
@signal_queue.each { |sig| kill sig, pid }
|
30
|
+
|
31
|
+
RunImpl::FORWARDED_SIGNALS.each do |sig|
|
32
|
+
trap(sig) { forward_signal sig, pid }
|
33
|
+
end
|
34
|
+
rescue Errno::ESRCH
|
35
|
+
end
|
36
|
+
|
37
|
+
def forward_signal(sig, pid)
|
38
|
+
kill(sig, pid)
|
39
|
+
rescue Errno::ESRCH
|
40
|
+
# If the application process is gone, then don't block the
|
41
|
+
# signal on this process.
|
42
|
+
trap(sig, 'DEFAULT')
|
43
|
+
Process.kill(sig, Process.pid)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Spring
|
2
|
+
module ApplicationImpl
|
3
|
+
def notify_manager_ready
|
4
|
+
manager.puts Process.pid
|
5
|
+
end
|
6
|
+
|
7
|
+
def receive_streams(client)
|
8
|
+
[]
|
9
|
+
end
|
10
|
+
|
11
|
+
def reopen_streams(streams)
|
12
|
+
# NOP
|
13
|
+
end
|
14
|
+
|
15
|
+
def eager_preload
|
16
|
+
preload
|
17
|
+
end
|
18
|
+
|
19
|
+
def screen_attached?
|
20
|
+
!system(%{screen -ls | grep "#{ENV['SPRING_SCREEN_NAME']}" | grep Detached > /dev/null})
|
21
|
+
end
|
22
|
+
|
23
|
+
def screen_move_to_bottom
|
24
|
+
puts "\033[22B"
|
25
|
+
end
|
26
|
+
|
27
|
+
def fork_child(client, streams, child_started)
|
28
|
+
manager.puts ENV["SPRING_SCREEN_NAME"]
|
29
|
+
child_started[0] = true
|
30
|
+
exitstatus = 0
|
31
|
+
begin
|
32
|
+
log "started #{Process.pid}"
|
33
|
+
yield
|
34
|
+
rescue SystemExit => ex
|
35
|
+
exitstatus = ex.status
|
36
|
+
end
|
37
|
+
|
38
|
+
log "#{Process.pid} exited with #{exitstatus}"
|
39
|
+
exit
|
40
|
+
end
|
41
|
+
|
42
|
+
def before_command
|
43
|
+
screen_move_to_bottom
|
44
|
+
sleep 0.1 until screen_attached?
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
module Spring
|
2
|
+
class ApplicationManager
|
3
|
+
class Worker
|
4
|
+
attr_reader :screen_pid, :pid, :uuid, :socket, :screen_name
|
5
|
+
attr_accessor :on_done
|
6
|
+
|
7
|
+
def initialize(env, args)
|
8
|
+
@spring_env = Env.new
|
9
|
+
channel, @remote_socket = WorkerChannel.pair
|
10
|
+
@uuid = File.basename(@remote_socket.path).gsub('.sock', '')
|
11
|
+
|
12
|
+
Bundler.with_clean_env do
|
13
|
+
spawn_screen(
|
14
|
+
env.merge("SPRING_SOCKET" => @remote_socket.path),
|
15
|
+
args
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
@socket = channel.to_io
|
20
|
+
end
|
21
|
+
|
22
|
+
def spawn_screen(env, args)
|
23
|
+
@screen_name = "spring_#{@uuid}"
|
24
|
+
|
25
|
+
@screen_pid =
|
26
|
+
Process.spawn(
|
27
|
+
env.merge("SPRING_SCREEN_NAME" => screen_name),
|
28
|
+
"screen", "-d", "-m", "-S", screen_name,
|
29
|
+
*args
|
30
|
+
)
|
31
|
+
|
32
|
+
log "(spawn #{@screen_pid})"
|
33
|
+
end
|
34
|
+
|
35
|
+
def await_boot
|
36
|
+
Process.detach(screen_pid)
|
37
|
+
@pid = socket.gets.to_i
|
38
|
+
start_wait_thread(pid, socket) unless pid.zero?
|
39
|
+
@remote_socket.close
|
40
|
+
end
|
41
|
+
|
42
|
+
def start_wait_thread(pid, child)
|
43
|
+
Thread.new {
|
44
|
+
begin
|
45
|
+
Process.kill(0, pid) while sleep(1)
|
46
|
+
rescue Errno::ESRCH
|
47
|
+
end
|
48
|
+
|
49
|
+
log "child #{pid} shutdown"
|
50
|
+
|
51
|
+
on_done.call(self) if on_done
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def log(message)
|
56
|
+
@spring_env.log "[worker:#{uuid}] #{message}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class WorkerPool
|
61
|
+
def initialize(app_env, *app_args)
|
62
|
+
@app_env = app_env
|
63
|
+
@app_args = app_args
|
64
|
+
@spring_env = Env.new
|
65
|
+
|
66
|
+
@workers = []
|
67
|
+
@workers_in_use = []
|
68
|
+
@spawning_workers = []
|
69
|
+
|
70
|
+
@check_mutex = Mutex.new
|
71
|
+
@workers_mutex = Mutex.new
|
72
|
+
|
73
|
+
run
|
74
|
+
end
|
75
|
+
|
76
|
+
def add_worker
|
77
|
+
worker = Worker.new(@app_env, @app_args)
|
78
|
+
worker.on_done = method(:worker_done)
|
79
|
+
@workers_mutex.synchronize { @spawning_workers << worker }
|
80
|
+
Thread.new do
|
81
|
+
worker.await_boot
|
82
|
+
log "+ worker #{worker.pid} (#{worker.uuid})"
|
83
|
+
@workers_mutex.synchronize do
|
84
|
+
@spawning_workers.delete(worker)
|
85
|
+
@workers << worker
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def worker_done(worker)
|
91
|
+
log "- worker #{worker.pid} (#{worker.uuid})"
|
92
|
+
@workers_mutex.synchronize do
|
93
|
+
@workers_in_use.delete(worker)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def get_worker(spawn_new = true)
|
98
|
+
add_worker if spawn_new && all_size == 0
|
99
|
+
|
100
|
+
worker = nil
|
101
|
+
while worker.nil? && all_size > 0
|
102
|
+
@workers_mutex.synchronize do
|
103
|
+
worker = @workers.shift
|
104
|
+
@workers_in_use << worker if worker
|
105
|
+
end
|
106
|
+
break if worker
|
107
|
+
sleep 1
|
108
|
+
end
|
109
|
+
|
110
|
+
Thread.new { check_min_free_workers } if spawn_new
|
111
|
+
|
112
|
+
worker
|
113
|
+
end
|
114
|
+
|
115
|
+
def check_min_free_workers
|
116
|
+
if @check_mutex.try_lock
|
117
|
+
# TODO: mutex, and dont do it if already in progress
|
118
|
+
# do this in thread
|
119
|
+
while all_size < Spring.pool_min_free_workers
|
120
|
+
unless Spring.pool_spawn_parallel
|
121
|
+
sleep 0.1 until @workers_mutex.synchronize { @spawning_workers.empty? }
|
122
|
+
end
|
123
|
+
add_worker
|
124
|
+
end
|
125
|
+
@check_mutex.unlock
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def all_size
|
130
|
+
@workers_mutex.synchronize { @workers.size + @spawning_workers.size }
|
131
|
+
end
|
132
|
+
|
133
|
+
def stop!
|
134
|
+
if spawning_worker_pids.include?(nil)
|
135
|
+
log "Waiting for workers to quit..."
|
136
|
+
sleep 0.1 while spawning_worker_pids.include?(nil)
|
137
|
+
end
|
138
|
+
|
139
|
+
@workers_mutex.synchronize do
|
140
|
+
(@spawning_workers + @workers_in_use + @workers).each do |worker|
|
141
|
+
kill_worker(worker)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
private
|
146
|
+
def kill_worker(worker)
|
147
|
+
log "- worker #{worker.pid} (#{worker.uuid})."
|
148
|
+
system("kill -9 #{worker.pid} > /dev/null 2>&1")
|
149
|
+
system("screen -S #{worker.screen_name} -X quit > /dev/null 2>&1")
|
150
|
+
rescue
|
151
|
+
end
|
152
|
+
|
153
|
+
def spawning_worker_pids
|
154
|
+
@spawning_workers.map { |worker| worker.pid }
|
155
|
+
end
|
156
|
+
|
157
|
+
def run
|
158
|
+
system("screen -wipe > /dev/null 2>&1")
|
159
|
+
|
160
|
+
check_min_free_workers
|
161
|
+
end
|
162
|
+
|
163
|
+
def log(message)
|
164
|
+
@spring_env.log "[worker:pool] #{message}"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def initialize(app_env)
|
169
|
+
@app_env = app_env
|
170
|
+
@spring_env = Env.new
|
171
|
+
@pool =
|
172
|
+
WorkerPool.new(
|
173
|
+
{
|
174
|
+
"RAILS_ENV" => app_env,
|
175
|
+
"RACK_ENV" => app_env,
|
176
|
+
"SPRING_ORIGINAL_ENV" => JSON.dump(Spring::ORIGINAL_ENV),
|
177
|
+
"SPRING_PRELOAD" => "1",
|
178
|
+
},
|
179
|
+
Spring.ruby_bin,
|
180
|
+
"-I", File.expand_path("../..", __FILE__),
|
181
|
+
"-e", "require 'spring-jruby/application/boot'"
|
182
|
+
)
|
183
|
+
end
|
184
|
+
|
185
|
+
# Returns the name of the screen running the command, or nil if the application process died.
|
186
|
+
def run(client)
|
187
|
+
name = nil
|
188
|
+
with_child do |child|
|
189
|
+
client.forward_to(child.socket)
|
190
|
+
child.socket.gets or raise Errno::EPIPE
|
191
|
+
|
192
|
+
name = child.socket.gets
|
193
|
+
end
|
194
|
+
|
195
|
+
unless name.nil?
|
196
|
+
log "got worker name #{name}"
|
197
|
+
name
|
198
|
+
end
|
199
|
+
rescue Errno::ECONNRESET, Errno::EPIPE => e
|
200
|
+
log "#{e} while reading from child; returning no name"
|
201
|
+
nil
|
202
|
+
ensure
|
203
|
+
client.close
|
204
|
+
end
|
205
|
+
|
206
|
+
def stop
|
207
|
+
log "stopping"
|
208
|
+
|
209
|
+
@pool.stop!
|
210
|
+
rescue Errno::ESRCH, Errno::ECHILD
|
211
|
+
# Don't care
|
212
|
+
end
|
213
|
+
|
214
|
+
protected
|
215
|
+
|
216
|
+
attr_reader :app_env, :spring_env
|
217
|
+
|
218
|
+
def log(message)
|
219
|
+
spring_env.log "[application_manager:#{app_env}] #{message}"
|
220
|
+
end
|
221
|
+
|
222
|
+
def with_child
|
223
|
+
yield(@pool.get_worker)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|