spool 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7e4c82fbd14fdb037f521f157995675fd3218bf1
4
- data.tar.gz: e1fd8caed3c81ec0d5ba7ced3d5a9907a69f16ab
3
+ metadata.gz: ded6da3c7760ef6ba4bf10f1d20c836f69901c0b
4
+ data.tar.gz: 31597cc84078b8289b7fb93089531d29e233e626
5
5
  SHA512:
6
- metadata.gz: 6b328d4596f62dd9bc01ad6bd9195f37a8b3d441ce18f2c929e2e01f36a9e49aa493f335bb55191bb848cf618440edd04da5440da3646085aab1f19ad4c7840e
7
- data.tar.gz: 4a8603056e5c0ded5f2fb226354795c1ab9261af04f2392772c4b4053b0a8a41a3f20f956f1ab3852024f3ba4e810d49b9f6600416837effd0e48fdd3ee425fc
6
+ metadata.gz: 8b172a8077738059e68bb160b60892355cfce88aabf6bc18c03eacba4c927aa936a36924093bc4b7a5d153eb107be287a65170bd1345f71f045d10a07c71129c
7
+ data.tar.gz: bf20887bd046790fb8ffc65fd803dc28b953283c00f02d075ca210c1b3389a8d45b7e744127d19d0d07ec2d9fc25a80e421b93fe423edc7853cf1687d4c07551
@@ -63,7 +63,6 @@ module Spool
63
63
  @logger ||= MonoLogger.new(log_file).tap do |logger|
64
64
  logger.level = MonoLogger.const_get log_level
65
65
  logger.formatter = log_formatter
66
- Datacenter.logger = logger
67
66
  end
68
67
  end
69
68
 
data/lib/spool/pool.rb CHANGED
@@ -13,11 +13,12 @@ module Spool
13
13
  TTOU: :decr
14
14
  }
15
15
 
16
- attr_reader :configuration, :processes
16
+ attr_reader :configuration, :working_processes, :zombie_processes
17
17
 
18
18
  def initialize(configuration=nil, &block)
19
19
  @configuration = configuration || DSL.configure(&block)
20
- @processes = []
20
+ @working_processes = []
21
+ @zombie_processes = Set.new
21
22
  @running = false
22
23
  @actions_queue = []
23
24
  end
@@ -30,6 +31,10 @@ module Spool
30
31
  !running?
31
32
  end
32
33
 
34
+ def all_processes
35
+ working_processes + zombie_processes.to_a
36
+ end
37
+
33
38
  [:incr, :decr, :reload, :restart, :stop, :stop!].each do |method|
34
39
  define_method method do |*args|
35
40
  actions_queue.push(name: "_#{method}".to_sym, args: args)
@@ -45,10 +50,10 @@ module Spool
45
50
  File.write configuration.pid_file, Process.pid if configuration.pid_file
46
51
 
47
52
  configuration.processes.times.map do
48
- processes << Spawner.spawn(configuration)
53
+ working_processes << Spawner.spawn(configuration)
49
54
  end
50
55
 
51
- logger.info(self.class) { "SPOOL START childrens: #{processes.map(&:pid)}" }
56
+ logger.info(self.class) { "SPOOL START => #{format_processes}" }
52
57
 
53
58
  while running?
54
59
  action = actions_queue.pop
@@ -69,6 +74,7 @@ module Spool
69
74
 
70
75
  private
71
76
 
77
+ attr_writer :working_processes, :zombie_processes
72
78
  attr_reader :actions_queue
73
79
 
74
80
  def handle_signals
@@ -81,36 +87,31 @@ module Spool
81
87
  end
82
88
 
83
89
  def check_status
84
- processes.delete_if { |p| !p.alive? }
85
-
86
- to_restart = processes.select(&configuration.restart_condition)
87
- logger.info(self.class) {"Restart condition successful in child processes: #{to_restart.map(&:pid)}"} if to_restart.any?
88
- stop_processes to_restart
90
+ clear_dead_processes
89
91
 
90
- if configuration.processes > processes.count
91
- logger.info(self.class) { "Initialize new children: #{processes.map(&:pid)}" }
92
+ check_processes_to_restart
93
+
94
+ if configuration.processes > all_processes_count
95
+ logger.info(self.class) { "Initializing new children. Current State => #{format_processes}" }
92
96
 
93
- (configuration.processes - processes.count).times do
94
- processes << Spawner.spawn(configuration)
97
+ (configuration.processes - all_processes_count).times do
98
+ working_processes << Spawner.spawn(configuration)
95
99
  end
96
100
 
97
- logger.info(self.class) { "New children: #{processes.map(&:pid)}" }
98
- elsif configuration.processes < processes.count
99
- logger.info(self.class) { "Kill childrens: #{processes.map(&:pid)}" }
101
+ logger.info(self.class) { "New children: #{working_processes.last.pid}" }
102
+ elsif configuration.processes < working_processes.count
103
+ count_to_kill = working_processes.count - configuration.processes
104
+ logger.info(self.class) { "Killing #{count_to_kill} children. Current state => #{format_processes}" }
100
105
 
101
- list = processes.take(processes.count - configuration.processes)
102
- stop_processes list
103
- wait_for_stopped list
104
- list.each { |p| processes.delete p }
106
+ stop_processes working_processes.take(count_to_kill)
105
107
 
106
- logger.info(self.class) { "After kill childrens: #{processes.map(&:pid)}" }
108
+ logger.info(self.class) { "After killing childers. Current State => #{format_processes}" }
107
109
  end
108
110
 
109
111
  rescue Exception => e
110
112
  log_error e
111
113
  end
112
114
 
113
-
114
115
  def _incr(count=1)
115
116
  configuration.processes += count
116
117
  end
@@ -126,14 +127,14 @@ module Spool
126
127
 
127
128
  def _restart
128
129
  logger.info(self.class) { "RESTART" }
129
- stop_processes processes
130
+ stop_processes working_processes
130
131
  end
131
132
 
132
133
  def _stop(timeout=0)
133
134
  logger.info(self.class) { "SPOOL STOP" }
134
135
 
135
- stop_processes processes
136
- Timeout.timeout(timeout) { wait_for_stopped processes }
136
+ stop_processes working_processes
137
+ Timeout.timeout(timeout) { wait_for_stopped all_processes }
137
138
  rescue Timeout::Error
138
139
  logger.error(self.class) { "ERROR IN SPOOL STOP. Timeout error" }
139
140
  ensure
@@ -142,23 +143,20 @@ module Spool
142
143
  end
143
144
 
144
145
  def _stop!
145
- logger.info(self.class) { "SPOOL STOP! kill this children (#{processes.map(&:pid)})" }
146
+ logger.info(self.class) { "SPOOL STOP! Going to kill => #{format_processes}" }
146
147
 
147
- processes.each do |p|
148
+ all_processes.each do |p|
148
149
  begin
149
- p.send_signal(configuration.kill_signal) if p.alive?
150
+ send_signal_to(p, configuration.kill_signal) if p.alive?
150
151
  rescue Datacenter::Shell::CommandError => e
151
- if p.alive?
152
- log_error e
153
- else
154
- logger.info(self.class) { "Signal KILL was sent to #{p.pid} but process was already dead" }
155
- end
152
+ log_error e
156
153
  end
157
154
  end
158
155
 
159
- wait_for_stopped processes
156
+ wait_for_stopped all_processes
160
157
 
161
- processes.clear
158
+ working_processes.clear
159
+ zombie_processes.clear
162
160
 
163
161
  File.delete configuration.pid_file if File.exist? configuration.pid_file
164
162
  @running = false
@@ -167,20 +165,45 @@ module Spool
167
165
  def stop_processes(processes_list)
168
166
  processes_list.each do |p|
169
167
  begin
170
- logger.info(self.class) {"Going to kill process #{p.pid}, alive? => #{p.alive?}"}
171
- p.send_signal configuration.stop_signal
168
+ send_signal_to p, configuration.stop_signal
169
+ zombie_processes << p
172
170
  rescue Exception => e
173
171
  log_error e
174
172
  end
175
173
  end
174
+
175
+ working_processes.delete_if{ |p| zombie_processes.include? p }
176
176
  end
177
177
 
178
- def wait_for_stopped(processes)
179
- while processes.any?(&:alive?)
178
+ def wait_for_stopped(processes_list)
179
+ while processes_list.any?(&:alive?)
180
180
  sleep 0.01
181
181
  end
182
182
  end
183
183
 
184
+ def check_processes_to_restart
185
+ to_restart = working_processes.select(&configuration.restart_condition)
186
+
187
+ if to_restart.any?
188
+ logger.info(self.class) {"Restart condition successful in child processes: #{to_restart.map(&:pid)}"}
189
+ stop_processes to_restart
190
+ end
191
+ end
192
+
193
+ def send_signal_to(process, signal)
194
+ logger.info(self.class) { "Going to send signal #{signal} to process #{process.pid}" }
195
+ process.send_signal signal
196
+ end
197
+
198
+ def clear_dead_processes
199
+ working_processes.delete_if { |p| !p.alive? }
200
+ zombie_processes.delete_if { |p| !p.alive? }
201
+ end
202
+
203
+ def all_processes_count
204
+ working_processes.count + zombie_processes.count
205
+ end
206
+
184
207
  def logger
185
208
  configuration.logger
186
209
  end
@@ -197,6 +220,10 @@ module Spool
197
220
  end.join("\n")
198
221
  end
199
222
 
223
+ def format_processes
224
+ "Working Processes: #{working_processes.map(&:pid)}, Zombie Processes: #{zombie_processes.map(&:pid)}"
225
+ end
226
+
200
227
  end
201
228
 
202
229
  end
data/lib/spool/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Spool
2
- VERSION = '1.0.2'
2
+ VERSION = '1.0.3'
3
3
  end
data/lib/spool.rb CHANGED
@@ -3,6 +3,7 @@ require 'securerandom'
3
3
  require 'timeout'
4
4
  require 'tmpdir'
5
5
  require 'mono_logger'
6
+ require 'set'
6
7
 
7
8
  require_relative 'spool/version'
8
9
  require_relative 'spool/dsl'
data/spec/pool_spec.rb CHANGED
@@ -18,7 +18,7 @@ describe Spool::Pool do
18
18
  @pool = Spool::Pool.new(&block).tap do |pool|
19
19
  t = Thread.new { pool.start }
20
20
  t.abort_on_exception = true
21
- while pool.processes.count < pool.configuration.processes
21
+ while pool.all_processes.count < pool.configuration.processes
22
22
  sleep 0.01
23
23
  end
24
24
  end
@@ -40,10 +40,10 @@ describe Spool::Pool do
40
40
  end
41
41
 
42
42
  pool.must_be :running?
43
- pool.processes.count.must_equal 1
44
- pool.processes[0].must_be :alive?
43
+ pool.all_processes.count.must_equal 1
44
+ pool.all_processes[0].must_be :alive?
45
45
 
46
- process = pool.processes[0]
46
+ process = pool.all_processes[0]
47
47
  pool.stop
48
48
 
49
49
  while pool.running?
@@ -51,7 +51,7 @@ describe Spool::Pool do
51
51
  end
52
52
 
53
53
  pool.must_be :stopped?
54
- pool.processes.must_be_empty
54
+ pool.all_processes.must_be_empty
55
55
  process.wont_be :alive?
56
56
  end
57
57
 
@@ -62,10 +62,10 @@ describe Spool::Pool do
62
62
  end
63
63
 
64
64
  pool.must_be :running?
65
- pool.processes.count.must_equal 1
66
- pool.processes[0].must_be :alive?
65
+ pool.all_processes.count.must_equal 1
66
+ pool.all_processes[0].must_be :alive?
67
67
 
68
- process = pool.processes[0]
68
+ process = pool.all_processes[0]
69
69
 
70
70
  pool.stop!
71
71
 
@@ -74,7 +74,7 @@ describe Spool::Pool do
74
74
  end
75
75
 
76
76
  pool.must_be :stopped?
77
- pool.processes.must_be_empty
77
+ pool.all_processes.must_be_empty
78
78
  process.wont_be :alive?
79
79
  end
80
80
 
@@ -84,18 +84,18 @@ describe Spool::Pool do
84
84
  command 'ruby -e "loop do; sleep 1; end"'
85
85
  end
86
86
 
87
- original_process = pool.processes[0]
87
+ original_process = pool.all_processes[0]
88
88
  original_process.send_signal :KILL
89
89
 
90
90
  begin
91
91
  sleep SLEEP_TIME
92
- new_pid = pool.processes.any? ? pool.processes[0].pid : original_process.pid
92
+ new_pid = pool.all_processes.any? ? pool.all_processes[0].pid : original_process.pid
93
93
  end while original_process.pid == new_pid
94
94
 
95
95
  original_process.wont_be :alive?
96
96
 
97
- pool.processes.count.must_equal 1
98
- pool.processes[0].must_be :alive?
97
+ pool.all_processes.count.must_equal 1
98
+ pool.all_processes[0].must_be :alive?
99
99
  end
100
100
 
101
101
  it 'Restart processes' do
@@ -105,18 +105,18 @@ describe Spool::Pool do
105
105
  stop_signal :TERM
106
106
  end
107
107
 
108
- pool.processes.count.must_equal 2
108
+ pool.all_processes.count.must_equal 2
109
109
 
110
- original_pids = pool.processes.map(&:pid)
110
+ original_pids = pool.all_processes.map(&:pid)
111
111
 
112
112
  pool.restart
113
113
 
114
114
  begin
115
115
  sleep SLEEP_TIME
116
- new_pids = (pool.processes.count == 2) ? pool.processes.map(&:pid) : original_pids
116
+ new_pids = (pool.all_processes.count == 2) ? pool.all_processes.map(&:pid) : original_pids
117
117
  end until (original_pids & new_pids).empty?
118
118
 
119
- pool.processes.each { |p| p.must_be :alive?}
119
+ pool.all_processes.each { |p| p.must_be :alive?}
120
120
  end
121
121
 
122
122
  it 'Stop with timeout' do
@@ -126,7 +126,7 @@ describe Spool::Pool do
126
126
  stop_signal :QUIT
127
127
  end
128
128
 
129
- process = pool.processes[0]
129
+ process = pool.all_processes[0]
130
130
 
131
131
  Benchmark.realtime do
132
132
  pool.stop 0.1
@@ -136,7 +136,7 @@ describe Spool::Pool do
136
136
  end.must_be :<, 1
137
137
 
138
138
  pool.must_be :stopped?
139
- pool.processes.must_be_empty
139
+ pool.all_processes.must_be_empty
140
140
  process.wont_be :alive?
141
141
  end
142
142
 
@@ -146,11 +146,11 @@ describe Spool::Pool do
146
146
  command 'ruby -e "loop do; sleep 1; end"'
147
147
  end
148
148
 
149
- pool.processes.count.must_equal 1
149
+ pool.all_processes.count.must_equal 1
150
150
 
151
151
  pool.incr 2
152
152
 
153
- assert_with_timeout(1) { pool.processes.count == 3 }
153
+ assert_with_timeout(1) { pool.all_processes.count == 3 }
154
154
  end
155
155
 
156
156
  it 'Decrease processes' do
@@ -160,11 +160,11 @@ describe Spool::Pool do
160
160
  stop_signal :TERM
161
161
  end
162
162
 
163
- pool.processes.count.must_equal 3
163
+ pool.all_processes.count.must_equal 3
164
164
 
165
165
  pool.decr 2
166
166
 
167
- assert_with_timeout(1) { pool.processes.count == 1 }
167
+ assert_with_timeout(1) { pool.all_processes.count == 1 }
168
168
  end
169
169
 
170
170
  it 'Change process when satisfied stop condition' do
@@ -187,18 +187,18 @@ describe Spool::Pool do
187
187
  stop_signal :TERM
188
188
  end
189
189
 
190
- original_process = pool.processes[0]
190
+ original_process = pool.all_processes[0]
191
191
 
192
192
  begin
193
193
  sleep SLEEP_TIME
194
- new_pid = pool.processes.any? ? pool.processes[0].pid : original_process.pid
194
+ new_pid = pool.all_processes.any? ? pool.all_processes[0].pid : original_process.pid
195
195
  end while original_process.pid == new_pid
196
196
 
197
197
  text_file = File.read(file_name)
198
198
  File.delete(file_name)
199
199
 
200
200
  text_file.must_equal 'Finished'
201
- pool.processes.count.must_equal 1
201
+ pool.all_processes.count.must_equal 1
202
202
  end
203
203
 
204
204
  it 'Reload config' do
@@ -208,19 +208,19 @@ describe Spool::Pool do
208
208
  pool = Spool::Pool.new(config).tap do |pool|
209
209
  t = Thread.new { pool.start }
210
210
  t.abort_on_exception = true
211
- while pool.processes.count < pool.configuration.processes
211
+ while pool.all_processes.count < pool.configuration.processes
212
212
  end
213
213
  end
214
214
 
215
- pool.processes.count.must_equal 1
215
+ pool.all_processes.count.must_equal 1
216
216
 
217
217
  pool.incr 1
218
218
 
219
- assert_with_timeout(1) { pool.processes.count == 2 }
219
+ assert_with_timeout(1) { pool.all_processes.count == 2 }
220
220
 
221
221
  pool.reload
222
222
 
223
- assert_with_timeout(1) { pool.processes.count == 1 }
223
+ assert_with_timeout(1) { pool.all_processes.count == 1 }
224
224
 
225
225
  pool.stop!
226
226
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spool
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabriel Naiman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-11-05 00:00:00.000000000 Z
11
+ date: 2018-11-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: datacenter