spool 1.0.2 → 1.0.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 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