spool 0.0.1
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/.coveralls.yml +2 -0
- data/.gitignore +22 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +65 -0
- data/Rakefile +18 -0
- data/bin/spool +14 -0
- data/lib/spool/configuration.rb +25 -0
- data/lib/spool/dsl.rb +48 -0
- data/lib/spool/pool.rb +117 -0
- data/lib/spool/spawner.rb +56 -0
- data/lib/spool/version.rb +3 -0
- data/lib/spool.rb +10 -0
- data/spec/coverage_helper.rb +8 -0
- data/spec/dsl_spec.rb +37 -0
- data/spec/minitest_helper.rb +12 -0
- data/spec/pool_spec.rb +123 -0
- data/spec/sample_config.rb +6 -0
- data/spec/sample_worker.rb +4 -0
- data/spool.gemspec +29 -0
- metadata +172 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cd69246ea37212c4be4790fffcf8605c16f31e2b
|
4
|
+
data.tar.gz: 556ff1e0891bd8e83407f837a522f1aa6bd770cc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c7e8b6b9799b61d376564d6f97edd784477acbb0fc66fffdc916771788f7b7f34659d22ed676ed27954b687a873d829df5647483bae3cfb19bd739abafcb8012
|
7
|
+
data.tar.gz: bbdb9307edea81364ca9eb6732f09686ef8a676273dffc25f38532867a3d58266874ac72c035568fe3322a43e499029d00560d89c73c53afd9662dedd6255193
|
data/.coveralls.yml
ADDED
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
spool
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby 2.1
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Gabriel Naiman
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# Spool
|
2
|
+
|
3
|
+
[](https://rubygems.org/gems/spool)
|
4
|
+
[](https://travis-ci.org/gabynaiman/spool)
|
5
|
+
[](https://coveralls.io/r/gabynaiman/spool?branch=master)
|
6
|
+
[](https://codeclimate.com/github/gabynaiman/spool)
|
7
|
+
[](https://gemnasium.com/gabynaiman/spool)
|
8
|
+
|
9
|
+
Manage and keep alive pool of processes
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
gem 'spool'
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install spool
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
#### Setup
|
28
|
+
|
29
|
+
*Worker*
|
30
|
+
|
31
|
+
loop do
|
32
|
+
puts "#{Process.pid} - #{Time.now}"
|
33
|
+
sleep 1
|
34
|
+
end
|
35
|
+
|
36
|
+
*Pool config*
|
37
|
+
|
38
|
+
processes 4
|
39
|
+
command 'ruby worker.rb'
|
40
|
+
# optional
|
41
|
+
dir File.dirname(__FILE__)
|
42
|
+
env VAR1: 'foo', VAR2: 'bar'
|
43
|
+
pidfile 'pool.pid'
|
44
|
+
restart_when { |p| p.memory > 512 }
|
45
|
+
|
46
|
+
#### Start
|
47
|
+
|
48
|
+
console:~$ spool pool_config.rb
|
49
|
+
|
50
|
+
#### Signals
|
51
|
+
|
52
|
+
- **INT/TERM:** quick shutdown, kills all processes immediately
|
53
|
+
- **QUIT:** graceful shutdown, waits for processes to finish
|
54
|
+
- **HUP:** reloads config file and gracefully restart all processes
|
55
|
+
- **USR2:** gracefully restart all processes with current configuration
|
56
|
+
- **TTIN:** increment the number of processes by one
|
57
|
+
- **TTOU:** decrement the number of processes by one
|
58
|
+
|
59
|
+
## Contributing
|
60
|
+
|
61
|
+
1. Fork it ( https://github.com/gabynaiman/spool/fork )
|
62
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
63
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
64
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
65
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rake/testtask'
|
3
|
+
|
4
|
+
Rake::TestTask.new(:spec) do |t|
|
5
|
+
t.libs << 'spec'
|
6
|
+
t.pattern = 'spec/**/*_spec.rb'
|
7
|
+
t.verbose = false
|
8
|
+
end
|
9
|
+
|
10
|
+
desc 'Console'
|
11
|
+
task :console do
|
12
|
+
require 'pry'
|
13
|
+
require 'spool'
|
14
|
+
ARGV.clear
|
15
|
+
Pry.start
|
16
|
+
end
|
17
|
+
|
18
|
+
task default: :spec
|
data/bin/spool
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
if ARGV.empty? || !File.exists?(ARGV.first)
|
4
|
+
puts "Invalid pool specification file: #{ARGV.first}"
|
5
|
+
exit 1
|
6
|
+
end
|
7
|
+
|
8
|
+
pid = fork do
|
9
|
+
require File.expand_path('../lib/spool', File.dirname(__FILE__))
|
10
|
+
config = Spool::DSL.configure ARGV.first
|
11
|
+
Spool::Pool.new(config).start
|
12
|
+
end
|
13
|
+
|
14
|
+
puts "Pool started (#{pid})"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Spool
|
2
|
+
class Configuration
|
3
|
+
|
4
|
+
attr_accessor :processes,
|
5
|
+
:env,
|
6
|
+
:dir,
|
7
|
+
:command,
|
8
|
+
:pidfile,
|
9
|
+
:restart_condition,
|
10
|
+
:source_file
|
11
|
+
|
12
|
+
def env
|
13
|
+
@env ||= {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def dir
|
17
|
+
@dir ||= source_file ? File.dirname(source_file) : Dir.pwd
|
18
|
+
end
|
19
|
+
|
20
|
+
def pidfile
|
21
|
+
@pidfile ||= File.join(dir, (source_file ? "#{File.basename(source_file, '.*')}.pid" : 'pool.pid'))
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
data/lib/spool/dsl.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
module Spool
|
2
|
+
class DSL
|
3
|
+
|
4
|
+
def self.configure(filename=nil, &block)
|
5
|
+
dsl = new filename, &block
|
6
|
+
dsl.configuration
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :configuration
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def initialize(filename=nil, &block)
|
14
|
+
@configuration = Configuration.new
|
15
|
+
if filename
|
16
|
+
configuration.source_file = File.expand_path filename
|
17
|
+
instance_eval IO.read(filename), filename
|
18
|
+
else
|
19
|
+
instance_eval &block
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def processes(count)
|
24
|
+
configuration.processes = count
|
25
|
+
end
|
26
|
+
|
27
|
+
def env(env)
|
28
|
+
configuration.env = env
|
29
|
+
end
|
30
|
+
|
31
|
+
def dir(dir)
|
32
|
+
configuration.dir = File.expand_path dir
|
33
|
+
end
|
34
|
+
|
35
|
+
def command(command)
|
36
|
+
configuration.command = command
|
37
|
+
end
|
38
|
+
|
39
|
+
def pidfile(pidfile)
|
40
|
+
configuration.pidfile = pidfile
|
41
|
+
end
|
42
|
+
|
43
|
+
def restart_when(&block)
|
44
|
+
configuration.restart_condition = block
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
data/lib/spool/pool.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
module Spool
|
2
|
+
class Pool
|
3
|
+
|
4
|
+
SIGNALS = {
|
5
|
+
INT: :stop!,
|
6
|
+
TERM: :stop!,
|
7
|
+
QUIT: :stop,
|
8
|
+
HUP: :reload,
|
9
|
+
USR2: :restart,
|
10
|
+
TTIN: :incr,
|
11
|
+
TTOU: :decr
|
12
|
+
}
|
13
|
+
|
14
|
+
attr_reader :configuration, :runner, :processes
|
15
|
+
|
16
|
+
def initialize(configuration=nil, &block)
|
17
|
+
@configuration = configuration || DSL.configure(&block)
|
18
|
+
@processes = []
|
19
|
+
@started = false
|
20
|
+
end
|
21
|
+
|
22
|
+
def started?
|
23
|
+
@started
|
24
|
+
end
|
25
|
+
|
26
|
+
def stopped?
|
27
|
+
!started?
|
28
|
+
end
|
29
|
+
|
30
|
+
def start
|
31
|
+
@started = true
|
32
|
+
|
33
|
+
handle_signals
|
34
|
+
|
35
|
+
File.write configuration.pidfile, Process.pid if configuration.pidfile
|
36
|
+
|
37
|
+
configuration.processes.times.map do
|
38
|
+
processes << Spawner.spawn(configuration)
|
39
|
+
end
|
40
|
+
|
41
|
+
while @started
|
42
|
+
check_status
|
43
|
+
sleep 0.05
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def stop(timeout=0)
|
48
|
+
processes.each(&:stop)
|
49
|
+
Timeout.timeout(timeout) { wait_for_stopped processes }
|
50
|
+
rescue Timeout::Error
|
51
|
+
ensure
|
52
|
+
stop!
|
53
|
+
end
|
54
|
+
|
55
|
+
def stop!
|
56
|
+
processes.each(&:kill)
|
57
|
+
processes.clear
|
58
|
+
File.delete configuration.pidfile if File.exists? configuration.pidfile
|
59
|
+
@started = false
|
60
|
+
end
|
61
|
+
|
62
|
+
def incr(count=1)
|
63
|
+
configuration.processes += count
|
64
|
+
end
|
65
|
+
|
66
|
+
def decr(count=1)
|
67
|
+
configuration.processes -= count
|
68
|
+
end
|
69
|
+
|
70
|
+
def reload
|
71
|
+
@configuration = DSL.configure configuration.source_file if configuration.source_file
|
72
|
+
end
|
73
|
+
|
74
|
+
def restart
|
75
|
+
processes.each(&:stop)
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def handle_signals
|
81
|
+
SIGNALS.each do |signal, event|
|
82
|
+
Signal.trap(signal) { send event }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def check_status
|
87
|
+
return if stopped?
|
88
|
+
|
89
|
+
processes.select(&configuration.restart_condition).each(&:stop) if configuration.restart_condition
|
90
|
+
processes.delete_if { |p| !p.alive? }
|
91
|
+
|
92
|
+
if configuration.processes > processes.count
|
93
|
+
(configuration.processes - processes.count).times do
|
94
|
+
processes << Spawner.spawn(configuration)
|
95
|
+
end
|
96
|
+
|
97
|
+
elsif configuration.processes < processes.count
|
98
|
+
list = processes.take(processes.count - configuration.processes)
|
99
|
+
list.each(&:stop)
|
100
|
+
wait_for_stopped list
|
101
|
+
list.each { |p| processes.delete p }
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
rescue
|
106
|
+
retry
|
107
|
+
end
|
108
|
+
|
109
|
+
def wait_for_stopped(processes)
|
110
|
+
while processes.any?(&:alive?)
|
111
|
+
sleep 0.01
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Spool
|
2
|
+
class Spawner
|
3
|
+
|
4
|
+
attr_reader :configuration
|
5
|
+
|
6
|
+
def initialize(configuration)
|
7
|
+
@configuration = configuration
|
8
|
+
end
|
9
|
+
|
10
|
+
def spawn
|
11
|
+
base_file = File.join Dir.tmpdir, SecureRandom.uuid
|
12
|
+
pid_file = "#{base_file}.pid"
|
13
|
+
out_file = "#{base_file}.out"
|
14
|
+
script_file = "#{base_file}.sh"
|
15
|
+
|
16
|
+
File.write script_file, %Q{
|
17
|
+
#!/usr/bin/env bash
|
18
|
+
#{configuration.command.strip} &
|
19
|
+
echo $! > #{pid_file}
|
20
|
+
}
|
21
|
+
|
22
|
+
::Process.spawn configuration.env,
|
23
|
+
"sh #{script_file}",
|
24
|
+
chdir: configuration.dir,
|
25
|
+
out: out_file,
|
26
|
+
err: out_file
|
27
|
+
|
28
|
+
pid = wait_for_pid pid_file
|
29
|
+
|
30
|
+
Datacenter::Process.new(pid).tap do |process|
|
31
|
+
raise "Invalid command: #{configuration.command}\n#{IO.read(out_file)}" unless process.alive?
|
32
|
+
end
|
33
|
+
|
34
|
+
ensure
|
35
|
+
[script_file, out_file, pid_file].each do |filename|
|
36
|
+
File.delete filename if File.exists? filename
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.spawn(configuration)
|
41
|
+
new(configuration).spawn
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def wait_for_pid(pid_file)
|
47
|
+
Timeout.timeout(60) do
|
48
|
+
until File.exists?(pid_file); end
|
49
|
+
IO.read(pid_file).to_i
|
50
|
+
end
|
51
|
+
rescue Timeout::Error
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
data/lib/spool.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'datacenter'
|
2
|
+
require 'securerandom'
|
3
|
+
require 'timeout'
|
4
|
+
require 'tmpdir'
|
5
|
+
|
6
|
+
require_relative 'spool/version'
|
7
|
+
require_relative 'spool/dsl'
|
8
|
+
require_relative 'spool/configuration'
|
9
|
+
require_relative 'spool/pool'
|
10
|
+
require_relative 'spool/spawner'
|
data/spec/dsl_spec.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'minitest_helper'
|
2
|
+
|
3
|
+
describe Spool::DSL do
|
4
|
+
|
5
|
+
MockProcess = Struct.new :memory
|
6
|
+
|
7
|
+
it 'Configure from block' do
|
8
|
+
config = Spool::DSL.configure do
|
9
|
+
processes 10
|
10
|
+
env VAR_1: 1, VAR_2: 2
|
11
|
+
dir '/tmp'
|
12
|
+
command 'tailf file.log'
|
13
|
+
pidfile '/tailf.pid'
|
14
|
+
restart_when { |p| p.memory > 512 }
|
15
|
+
end
|
16
|
+
|
17
|
+
assert_configuration config
|
18
|
+
config.source_file.must_equal nil
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'Configure from file' do
|
22
|
+
config_file = File.expand_path('../sample_config.rb', __FILE__)
|
23
|
+
config = Spool::DSL.configure config_file
|
24
|
+
assert_configuration config
|
25
|
+
config.source_file.must_equal config_file
|
26
|
+
end
|
27
|
+
|
28
|
+
def assert_configuration(config)
|
29
|
+
config.processes.must_equal 10
|
30
|
+
config.env.must_equal VAR_1: 1, VAR_2: 2
|
31
|
+
config.dir.must_equal '/tmp'
|
32
|
+
config.command.must_equal 'tailf file.log'
|
33
|
+
config.restart_condition.call(MockProcess.new(600)).must_equal true
|
34
|
+
config.restart_condition.call(MockProcess.new(100)).must_equal false
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
data/spec/pool_spec.rb
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'minitest_helper'
|
2
|
+
|
3
|
+
describe Spool::Pool do
|
4
|
+
|
5
|
+
after do
|
6
|
+
@pool.stop! if @pool
|
7
|
+
machine = Datacenter::Machine.new
|
8
|
+
machine.processes('ruby -e').each(&:kill)
|
9
|
+
end
|
10
|
+
|
11
|
+
def start_pool(&block)
|
12
|
+
@pool = Spool::Pool.new(&block).tap do |pool|
|
13
|
+
t = Thread.new { pool.start }
|
14
|
+
t.abort_on_exception = true
|
15
|
+
while pool.processes.count < pool.configuration.processes
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def assert_with_timeout(timeout, &block)
|
21
|
+
Timeout.timeout(timeout) do
|
22
|
+
until block.call
|
23
|
+
sleep 0.01
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'Start and stop' do
|
29
|
+
pool = start_pool do
|
30
|
+
processes 1
|
31
|
+
command 'ruby -e "loop do; sleep 1; end"'
|
32
|
+
end
|
33
|
+
|
34
|
+
pool.must_be :started?
|
35
|
+
pool.processes.count.must_equal 1
|
36
|
+
pool.processes[0].must_be :alive?
|
37
|
+
|
38
|
+
process = pool.processes[0]
|
39
|
+
|
40
|
+
pool.stop
|
41
|
+
|
42
|
+
pool.must_be :stopped?
|
43
|
+
pool.processes.must_be_empty
|
44
|
+
process.wont_be :alive?
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'Recover killed process' do
|
48
|
+
pool = start_pool do
|
49
|
+
processes 1
|
50
|
+
command 'ruby -e "loop do; sleep 1; end"'
|
51
|
+
end
|
52
|
+
|
53
|
+
original_process = pool.processes[0]
|
54
|
+
original_process.kill
|
55
|
+
|
56
|
+
original_process.wont_be :alive?
|
57
|
+
|
58
|
+
until pool.processes[0] && pool.processes[0].pid != original_process.pid; end
|
59
|
+
|
60
|
+
pool.processes.count.must_equal 1
|
61
|
+
pool.processes[0].must_be :alive?
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'Stop with timeout' do
|
65
|
+
pool = start_pool do
|
66
|
+
processes 1
|
67
|
+
command 'ruby -e "Signal.trap(:TERM) { sleep 5; exit 0 }; loop { sleep 1 }"'
|
68
|
+
end
|
69
|
+
|
70
|
+
process = pool.processes[0]
|
71
|
+
|
72
|
+
Benchmark.realtime { pool.stop 0.1 }.must_be :<, 1
|
73
|
+
|
74
|
+
pool.must_be :stopped?
|
75
|
+
pool.processes.must_be_empty
|
76
|
+
process.wont_be :alive?
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'Increase processes' do
|
80
|
+
pool = start_pool do
|
81
|
+
processes 1
|
82
|
+
command 'ruby -e "loop do; sleep 1; end"'
|
83
|
+
end
|
84
|
+
|
85
|
+
pool.processes.count.must_equal 1
|
86
|
+
|
87
|
+
pool.incr 2
|
88
|
+
|
89
|
+
assert_with_timeout(1) { pool.processes.count == 3 }
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'Decrease processes' do
|
93
|
+
pool = start_pool do
|
94
|
+
processes 3
|
95
|
+
command 'ruby -e "loop do; sleep 1; end"'
|
96
|
+
end
|
97
|
+
|
98
|
+
pool.processes.count.must_equal 3
|
99
|
+
|
100
|
+
pool.decr 2
|
101
|
+
|
102
|
+
assert_with_timeout(1) { pool.processes.count == 1 }
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'Change process when satisfied stop condition' do
|
106
|
+
pool = start_pool do
|
107
|
+
processes 1
|
108
|
+
command 'ruby -e "a = 50_000_000.times.to_a; loop do; end"'
|
109
|
+
restart_when { |p| p.memory > 300 }
|
110
|
+
end
|
111
|
+
|
112
|
+
memory = 0
|
113
|
+
process = pool.processes[0]
|
114
|
+
while pool.processes.empty? || pool.processes[0].pid == process.pid
|
115
|
+
memory = process.memory
|
116
|
+
end
|
117
|
+
|
118
|
+
memory.must_be :>, 100
|
119
|
+
pool.processes.count.must_equal 1
|
120
|
+
pool.processes[0].pid.wont_equal process.pid
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
data/spool.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'spool/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'spool'
|
8
|
+
spec.version = Spool::VERSION
|
9
|
+
spec.authors = ['Gabriel Naiman']
|
10
|
+
spec.email = ['gnaiman@keepcon.com']
|
11
|
+
spec.summary = 'Manage and keep alive pool of processes'
|
12
|
+
spec.description = ''
|
13
|
+
spec.homepage = 'https://github.com/gabynaiman/spool'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_dependency 'datacenter', '~> 0.1.0'
|
22
|
+
|
23
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
24
|
+
spec.add_development_dependency 'rake'
|
25
|
+
spec.add_development_dependency 'minitest', '~> 4.7'
|
26
|
+
spec.add_development_dependency 'turn', '~> 0.9'
|
27
|
+
spec.add_development_dependency 'simplecov'
|
28
|
+
spec.add_development_dependency 'pry-nav'
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: spool
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gabriel Naiman
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: datacenter
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.1.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.1.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.5'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '4.7'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '4.7'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: turn
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.9'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.9'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: pry-nav
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: ''
|
112
|
+
email:
|
113
|
+
- gnaiman@keepcon.com
|
114
|
+
executables:
|
115
|
+
- spool
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- ".coveralls.yml"
|
120
|
+
- ".gitignore"
|
121
|
+
- ".ruby-gemset"
|
122
|
+
- ".ruby-version"
|
123
|
+
- ".travis.yml"
|
124
|
+
- Gemfile
|
125
|
+
- LICENSE.txt
|
126
|
+
- README.md
|
127
|
+
- Rakefile
|
128
|
+
- bin/spool
|
129
|
+
- lib/spool.rb
|
130
|
+
- lib/spool/configuration.rb
|
131
|
+
- lib/spool/dsl.rb
|
132
|
+
- lib/spool/pool.rb
|
133
|
+
- lib/spool/spawner.rb
|
134
|
+
- lib/spool/version.rb
|
135
|
+
- spec/coverage_helper.rb
|
136
|
+
- spec/dsl_spec.rb
|
137
|
+
- spec/minitest_helper.rb
|
138
|
+
- spec/pool_spec.rb
|
139
|
+
- spec/sample_config.rb
|
140
|
+
- spec/sample_worker.rb
|
141
|
+
- spool.gemspec
|
142
|
+
homepage: https://github.com/gabynaiman/spool
|
143
|
+
licenses:
|
144
|
+
- MIT
|
145
|
+
metadata: {}
|
146
|
+
post_install_message:
|
147
|
+
rdoc_options: []
|
148
|
+
require_paths:
|
149
|
+
- lib
|
150
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
151
|
+
requirements:
|
152
|
+
- - ">="
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: '0'
|
155
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
requirements: []
|
161
|
+
rubyforge_project:
|
162
|
+
rubygems_version: 2.2.2
|
163
|
+
signing_key:
|
164
|
+
specification_version: 4
|
165
|
+
summary: Manage and keep alive pool of processes
|
166
|
+
test_files:
|
167
|
+
- spec/coverage_helper.rb
|
168
|
+
- spec/dsl_spec.rb
|
169
|
+
- spec/minitest_helper.rb
|
170
|
+
- spec/pool_spec.rb
|
171
|
+
- spec/sample_config.rb
|
172
|
+
- spec/sample_worker.rb
|