navy 1.0.7 → 1.1.0

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.
@@ -56,229 +56,275 @@ pid "/tmp/navy.pid"
56
56
 
57
57
  # end
58
58
 
59
- module Jack
59
+ # module Jack
60
60
 
61
- SELF_PIPE = []
61
+ # SELF_PIPE = []
62
62
 
63
- extend self
63
+ # extend self
64
64
 
65
- def call(officer)
66
- trap(:QUIT) { exit }
67
- trap(:TERM) { exit }
65
+ # def call(officer)
66
+ # trap(:QUIT) { sleep 120; exit }
67
+ # trap(:TERM) { exit }
68
68
 
69
- # raise "HELLO"
70
- n = 0
71
- loop do
72
- puts "#{n} jack called (officer=#{officer.number}) pid: #{officer.officer_pid}"
73
- # Jack.logger.info "#{n} jack logger (officer=#{officer.number}) pid: #{officer.officer_pid}"
74
- # Navy.logger.info "START_CTX: #{START_CTX.inspect}"
75
- # Navy.logger.info "Navy::Admiral::CAPTAINS: #{Navy::Admiral::CAPTAINS.inspect}"
76
- # Navy.logger.info "Navy::Admiral::OFFICERS: #{Navy::Captain::OFFICERS.inspect}"
77
- sleep officer.number == 0 ? 0.5 : 1
78
- n += 1
79
- end
80
- end
69
+ # # raise "HELLO"
70
+ # n = 0
71
+ # loop do
72
+ # Navy.logger.info "#{n} jack called (officer=#{officer.number}) pid: #{officer.officer_pid}"
73
+ # # Jack.logger.info "#{n} jack logger (officer=#{officer.number}) pid: #{officer.officer_pid}"
74
+ # # Navy.logger.info "START_CTX: #{START_CTX.inspect}"
75
+ # # Navy.logger.info "Navy::Admiral::CAPTAINS: #{Navy::Admiral::CAPTAINS.inspect}"
76
+ # # Navy.logger.info "Navy::Admiral::OFFICERS: #{Navy::Captain::OFFICERS.inspect}"
77
+ # sleep officer.number == 0 ? 0.5 : 1
78
+ # n += 1
79
+ # end
80
+ # end
81
81
 
82
- def logger
83
- @logger ||= Logger.new('/tmp/jack.log')
84
- end
82
+ # def logger
83
+ # @logger ||= Logger.new('/tmp/jack.log')
84
+ # end
85
85
 
86
- def logger=(val)
87
- @logger = val
88
- end
86
+ # def logger=(val)
87
+ # @logger = val
88
+ # end
89
89
 
90
- def readers
91
- @readers ||= {}
92
- end
90
+ # def readers
91
+ # @readers ||= {}
92
+ # end
93
93
 
94
- def reader=(val)
95
- @reader = val
96
- end
94
+ # def reader=(val)
95
+ # @reader = val
96
+ # end
97
97
 
98
- def writer=(val)
99
- @writer = val
100
- end
98
+ # def writer=(val)
99
+ # @writer = val
100
+ # end
101
101
 
102
- def reader
103
- @reader
104
- end
102
+ # def reader
103
+ # @reader
104
+ # end
105
105
 
106
- def writer
107
- @writer
108
- end
106
+ # def writer
107
+ # @writer
108
+ # end
109
109
 
110
- def main_reader=(val)
111
- @main_reader = val
112
- end
110
+ # def main_reader=(val)
111
+ # @main_reader = val
112
+ # end
113
113
 
114
- def main_writer=(val)
115
- @main_writer = val
116
- end
114
+ # def main_writer=(val)
115
+ # @main_writer = val
116
+ # end
117
117
 
118
- def main_reader
119
- @main_reader
120
- end
118
+ # def main_reader
119
+ # @main_reader
120
+ # end
121
121
 
122
- def main_writer
123
- @main_writer
124
- end
122
+ # def main_writer
123
+ # @main_writer
124
+ # end
125
125
 
126
- def threads
127
- @threads ||= {}
128
- end
126
+ # def threads
127
+ # @threads ||= {}
128
+ # end
129
129
 
130
- def start
131
- @thread ||= Thread.new do
132
- loop do
133
- IO.select([ SELF_PIPE[0] ], nil, nil, 0.1) or next
134
- data = SELF_PIPE[0].gets
135
- next unless data
136
- data.force_encoding("BINARY") if data.respond_to?(:force_encoding)
137
- pid, message = data.split(',', 2)
138
- Jack.logger.info "YOUR PID WAS: #{pid}; #{message.strip}"
139
- # Jack.logger.info data
140
- end
141
- end
142
- end
130
+ # def start
131
+ # @thread ||= Thread.new do
132
+ # loop do
133
+ # IO.select([ SELF_PIPE[0] ], nil, nil, 0.1) or next
134
+ # data = SELF_PIPE[0].gets
135
+ # next unless data
136
+ # data.force_encoding("BINARY") if data.respond_to?(:force_encoding)
137
+ # pid, message = data.split(',', 2)
138
+ # Jack.logger.info "YOUR PID WAS: #{pid}; #{message.strip}"
139
+ # # Jack.logger.info data
140
+ # end
141
+ # end
142
+ # end
143
143
 
144
- def stop
145
- if @thread
146
- @thread.terminate rescue nil
147
- end
148
- SELF_PIPE.each { |io| io.close rescue nil }
149
- end
144
+ # def stop
145
+ # if @thread
146
+ # @thread.terminate rescue nil
147
+ # end
148
+ # SELF_PIPE.each { |io| io.close rescue nil }
149
+ # end
150
150
 
151
- # def main_thread(captain = nil)
152
- # @main_thread = nil if @main_thread and @main_thread.stop?
153
- # if @main_thread.nil?
154
- # # Jack.main_reader.close rescue nil
155
- # # Jack.main_writer.close rescue nil
156
- # Jack.main_reader, Jack.main_writer = IO.pipe
157
- # Jack.main_reader.sync = true
158
- # Jack.main_writer.sync = true
159
- # end
160
- # @main_thread ||= Thread.new do
161
- # readers = [Jack.main_reader]
162
- # loop do
163
- # rs, ws = IO.select(readers, [], [], 1)
164
- # (rs || []).each do |r|
165
- # data = r.gets
166
- # next unless data
167
- # data.force_encoding("BINARY") if data.respond_to?(:force_encoding)
168
- # ps, message = data.split(",", 2)
169
- # Jack.logger.info "pid: #{ps}, message: #{message.to_s.strip}"
170
- # end
171
- # end
172
- # end
173
- # end
174
- end
151
+ # # def main_thread(captain = nil)
152
+ # # @main_thread = nil if @main_thread and @main_thread.stop?
153
+ # # if @main_thread.nil?
154
+ # # # Jack.main_reader.close rescue nil
155
+ # # # Jack.main_writer.close rescue nil
156
+ # # Jack.main_reader, Jack.main_writer = IO.pipe
157
+ # # Jack.main_reader.sync = true
158
+ # # Jack.main_writer.sync = true
159
+ # # end
160
+ # # @main_thread ||= Thread.new do
161
+ # # readers = [Jack.main_reader]
162
+ # # loop do
163
+ # # rs, ws = IO.select(readers, [], [], 1)
164
+ # # (rs || []).each do |r|
165
+ # # data = r.gets
166
+ # # next unless data
167
+ # # data.force_encoding("BINARY") if data.respond_to?(:force_encoding)
168
+ # # ps, message = data.split(",", 2)
169
+ # # Jack.logger.info "pid: #{ps}, message: #{message.to_s.strip}"
170
+ # # end
171
+ # # end
172
+ # # end
173
+ # # end
174
+ # end
175
175
 
176
176
  captain :jack do
177
177
 
178
- stderr_path "/tmp/navy-jack-err.log"
179
- # stdout_path "/tmp/navy-jack-out.log"
180
-
181
- preload do |captain|
182
- captain.logger.warn "captain=#{captain.label} preload"
183
- Jack::SELF_PIPE.each { |io| io.close rescue nil }
184
- # Jack::SELF_PIPE.replace(Kgio::Pipe.new)
185
- Jack::SELF_PIPE.replace(IO.pipe)
186
- Jack::SELF_PIPE.each { |io| io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC); io.sync = true }
187
- Jack.logger.info "preload"
188
- Jack.start
189
- end
178
+ # stderr_path "/tmp/navy-jack-err.log"
179
+ # # stdout_path "/tmp/navy-jack-out.log"
180
+
181
+ # preload do |captain|
182
+ # captain.logger.warn "captain=#{captain.label} preload"
183
+ # Jack::SELF_PIPE.each { |io| io.close rescue nil }
184
+ # # Jack::SELF_PIPE.replace(Kgio::Pipe.new)
185
+ # Jack::SELF_PIPE.replace(IO.pipe)
186
+ # Jack::SELF_PIPE.each { |io| io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC); io.sync = true }
187
+ # Jack.logger.info "preload"
188
+ # Jack.start
189
+ # end
190
190
 
191
- before_fork do |captain, officer|
192
- # Jack.main_thread(captain)
193
- captain.logger.warn "captain=#{captain.label} before_fork"
194
- officer.logger.warn "(#{captain.label}) officer=#{officer.number} before_fork"
195
- # if r = Jack.readers.delete(officer.number)
196
- # r.close
197
- # end
198
- # Jack.readers[officer.number], Jack.writer = IO.pipe
199
- # Jack.reader = Jack.readers[officer.number]
200
- # Jack.reader.sync = true
201
- end
191
+ # before_fork do |captain, officer|
192
+ # # Jack.main_thread(captain)
193
+ # captain.logger.warn "captain=#{captain.label} before_fork"
194
+ # officer.logger.warn "(#{captain.label}) officer=#{officer.number} before_fork"
195
+ # # if r = Jack.readers.delete(officer.number)
196
+ # # r.close
197
+ # # end
198
+ # # Jack.readers[officer.number], Jack.writer = IO.pipe
199
+ # # Jack.reader = Jack.readers[officer.number]
200
+ # # Jack.reader.sync = true
201
+ # end
202
202
 
203
- after_fork do |captain, officer|
204
- # Jack.reader.close # we don't read
205
- # Jack.writer.sync = true
206
- captain.logger.warn "captain=#{captain.label} after_fork"
207
- officer.logger.warn "(#{captain.label}) officer=#{officer.number} after_fork"
208
- # $stdout.reopen Jack.writer
209
- # $stderr.reopen Jack.writer
210
-
211
- reader, writer = IO.pipe
212
- $stdout.reopen writer
213
- $stdout.reopen writer
214
-
215
- Thread.new do
216
- until reader.eof?
217
- Jack::SELF_PIPE[1].puts "%s,%s" % [ officer.officer_pid, reader.gets ]
218
- end
219
- end
220
- end
203
+ # after_fork do |captain, officer|
204
+ # # Jack.reader.close # we don't read
205
+ # # Jack.writer.sync = true
206
+ # captain.logger.warn "captain=#{captain.label} after_fork"
207
+ # officer.logger.warn "(#{captain.label}) officer=#{officer.number} after_fork"
208
+ # # $stdout.reopen Jack.writer
209
+ # # $stderr.reopen Jack.writer
210
+
211
+ # reader, writer = IO.pipe
212
+ # $stdout.reopen writer
213
+ # $stdout.reopen writer
214
+
215
+ # Thread.new do
216
+ # until reader.eof?
217
+ # Jack::SELF_PIPE[1].puts "%s,%s" % [ officer.officer_pid, reader.gets ]
218
+ # end
219
+ # end
220
+ # end
221
221
 
222
- after_stop do |captain, graceful|
223
- Jack.stop if graceful
224
- end
222
+ # after_stop do |captain, graceful|
223
+ # Jack.stop if graceful
224
+ # end
225
225
 
226
- post_fork do |captain, officer|
227
- # Jack.writer.close # we don't write
228
- # if t = Jack.threads[officer.number]
229
- # t.terminate unless t.stop?
230
- # else
231
- # Jack.threads[officer.number] = Thread.new do
232
- # reader = Jack.reader
233
- # until reader.eof?
234
- # Jack::SELF_PIPE[1].puts "%s,%s" % [ officer.officer_pid, reader.gets ]
235
- # end
236
- # end
237
- # end
238
- # Jack.reader.lcose
239
- # Thread.new do
240
- # # Jack.main_reader.close
241
- # # Jack.main_writer.close
242
- # loop do
243
- # rs, ws = IO.select([Jack.reader], [], [], 1)
244
- # (rs || []).each do |r|
245
- # data = r.gets
246
- # next unless data
247
- # data.force_encoding("BINARY") if data.respond_to?(:force_encoding)
248
- # # ps, message = data.split(",", 2)
249
- # # color = colors[ps.split(".").first]
250
- # # info message, ps, color
251
- # # Jack.mutex.synchronize do
252
- # # Jack.logger.info "pid: #{ps}, message: #{message}"
253
- # # Jack.logger.info data.strip
254
- # # end
255
- # Jack.main_writer.puts "pidpidpid: #{officer.officer_pid}, message: #{data}"
256
- # end
257
- # end
258
- # end
259
- # Thread.new do
260
- # reader, writer = Jack.reader, Jack.writer
261
- # loop do
262
- # rs, ws = IO.select([reader], [], [], 1)
263
- # (rs || []).each do |r|
264
- # data = r.gets
265
- # next unless data
266
- # data.force_encoding("BINARY") if data.respond_to?(:force_encoding)
267
- # # ps, message = data.split(",", 2)
268
- # # color = colors[ps.split(".").first]
269
- # # info message, ps, color
270
- # # Jack.mutex.synchronize do
271
- # # Jack.logger.info "pid: #{ps}, message: #{message}"
272
- # writer.write "%s,%s" [ '13', data ]
273
- # # end
274
- # end
275
- # end
276
- # end
277
- end
226
+ # post_fork do |captain, officer|
227
+ # # Jack.writer.close # we don't write
228
+ # # if t = Jack.threads[officer.number]
229
+ # # t.terminate unless t.stop?
230
+ # # else
231
+ # # Jack.threads[officer.number] = Thread.new do
232
+ # # reader = Jack.reader
233
+ # # until reader.eof?
234
+ # # Jack::SELF_PIPE[1].puts "%s,%s" % [ officer.officer_pid, reader.gets ]
235
+ # # end
236
+ # # end
237
+ # # end
238
+ # # Jack.reader.lcose
239
+ # # Thread.new do
240
+ # # # Jack.main_reader.close
241
+ # # # Jack.main_writer.close
242
+ # # loop do
243
+ # # rs, ws = IO.select([Jack.reader], [], [], 1)
244
+ # # (rs || []).each do |r|
245
+ # # data = r.gets
246
+ # # next unless data
247
+ # # data.force_encoding("BINARY") if data.respond_to?(:force_encoding)
248
+ # # # ps, message = data.split(",", 2)
249
+ # # # color = colors[ps.split(".").first]
250
+ # # # info message, ps, color
251
+ # # # Jack.mutex.synchronize do
252
+ # # # Jack.logger.info "pid: #{ps}, message: #{message}"
253
+ # # # Jack.logger.info data.strip
254
+ # # # end
255
+ # # Jack.main_writer.puts "pidpidpid: #{officer.officer_pid}, message: #{data}"
256
+ # # end
257
+ # # end
258
+ # # end
259
+ # # Thread.new do
260
+ # # reader, writer = Jack.reader, Jack.writer
261
+ # # loop do
262
+ # # rs, ws = IO.select([reader], [], [], 1)
263
+ # # (rs || []).each do |r|
264
+ # # data = r.gets
265
+ # # next unless data
266
+ # # data.force_encoding("BINARY") if data.respond_to?(:force_encoding)
267
+ # # # ps, message = data.split(",", 2)
268
+ # # # color = colors[ps.split(".").first]
269
+ # # # info message, ps, color
270
+ # # # Jack.mutex.synchronize do
271
+ # # # Jack.logger.info "pid: #{ps}, message: #{message}"
272
+ # # writer.write "%s,%s" [ '13', data ]
273
+ # # # end
274
+ # # end
275
+ # # end
276
+ # # end
277
+ # end
278
+
279
+ # preload do |captain|
280
+ # require 'fileutils'
281
+ # require 'rainbow'
282
+ # Sickill::Rainbow.enabled = true
283
+ # end
278
284
 
279
285
  respawn_limit 15, 5
280
286
 
281
- officers 4, Jack
287
+ patience 5
288
+
289
+ # heartbeat do |captain|
290
+ # captain.logger.info "captain=#{captain.label} heartbeat".color(:red)
291
+ # captain.class::OFFICERS.each do |officer_pid, officer|
292
+ # # begin
293
+ # name = "/tmp/ps#{officer_pid}"
294
+ # system("ps -o rss= -p #{officer_pid} > #{name}")
295
+ # mem_usage = (::File.read(name) rescue 0).to_s.strip.to_i
296
+ # ::FileUtils.rm_f(name)
297
+
298
+ # if mem_usage > 2000
299
+ # captain.send(:kill_officer, :TERM, officer_pid)
300
+ # captain.logger.info "captain=#{captain.label} officer=#{officer.number} over memory limit, sending TERM (pid: #{officer_pid}, mem: #{mem_usage} KB)".color(:yellow)
301
+ # else
302
+
303
+ # # mem_usage = `ps -o rss= -p #{officer_pid}`.to_s.strip
304
+ # # mem_usage = 20
305
+ # captain.logger.info "captain=#{captain.label} checking officer=#{officer.number} (pid: #{officer_pid}, mem: #{mem_usage} KB)".color(:green)
306
+ # # rescue => e
307
+ # # captain.logger.error "captain=#{captain.label} checking officer=#{officer.number} (pid: #{pid}) error: #{e.inspect}".color(:red)
308
+ # end
309
+ # end
310
+ # end
311
+
312
+ officers 4 do |officer|
313
+ trap(:QUIT) { sleep 120; exit }
314
+ trap(:TERM) { exit }
315
+
316
+ # raise "HELLO"
317
+ n = 0
318
+ loop do
319
+ Navy.logger.info "#{n} jack called (officer=#{officer.number}) pid: #{officer.officer_pid}"
320
+ # Jack.logger.info "#{n} jack logger (officer=#{officer.number}) pid: #{officer.officer_pid}"
321
+ # Navy.logger.info "START_CTX: #{START_CTX.inspect}"
322
+ # Navy.logger.info "Navy::Admiral::CAPTAINS: #{Navy::Admiral::CAPTAINS.inspect}"
323
+ # Navy.logger.info "Navy::Admiral::OFFICERS: #{Navy::Captain::OFFICERS.inspect}"
324
+ sleep officer.number == 0 ? 0.5 : 1
325
+ n += 1
326
+ end
327
+ end
282
328
  # officers 2 do |officer|
283
329
  # trap(:QUIT) { exit }
284
330
  # trap(:TERM) { exit }
@@ -26,8 +26,11 @@ class Navy::Admiral < Navy::Rank
26
26
  Dir.pwd
27
27
  end
28
28
 
29
- attr_accessor :admiral_pid, :captains, :timeout, :respawn_limit, :respawn_limit_seconds
30
- attr_reader :options
29
+ ## callbacks ##
30
+ attr_accessor :before_exec
31
+
32
+ attr_accessor :admiral_pid, :captains
33
+ attr_reader :options
31
34
 
32
35
  def initialize(options = {})
33
36
  self.orig_stderr = $stderr.dup
@@ -78,6 +81,7 @@ class Navy::Admiral < Navy::Rank
78
81
  when nil
79
82
  # avoid murdering workers after our master process (or the
80
83
  # machine) comes out of suspend/hibernation
84
+ heartbeat.call(self) if heartbeat
81
85
  if (last_check + @timeout) >= (last_check = Time.now)
82
86
  sleep_time = murder_lazy_captains
83
87
  logger.debug("would normally murder lazy captains") if $DEBUG
@@ -132,12 +136,15 @@ class Navy::Admiral < Navy::Rank
132
136
  # Terminates all captains, but does not exit admiral process
133
137
  def stop(graceful = true)
134
138
  before_stop.call(self, graceful) if before_stop
135
- limit = Time.now + timeout
136
- until CAPTAINS.empty? || Time.now > limit
139
+ limit = Time.now + patience
140
+ until CAPTAINS.empty? || (n = Time.now) > limit
137
141
  kill_each_captain(graceful ? :QUIT : :TERM)
138
142
  sleep(0.1)
139
143
  reap_all_captains
140
144
  end
145
+ if n and n > limit
146
+ logger.debug "admiral patience exceeded by #{n - limit} seconds (limit #{patience} seconds)" if $DEBUG
147
+ end
141
148
  kill_each_captain(:KILL)
142
149
  after_stop.call(self, graceful) if after_stop
143
150
  end
@@ -17,6 +17,9 @@ class Navy::Admiral::Orders < Navy::Orders
17
17
  admiral.logger.debug("admiral before (#{graceful ? 'graceful' : 'hard'}) stop") if $DEBUG
18
18
  end,
19
19
  captains: {},
20
+ heartbeat: ->(admiral) do
21
+ admiral.logger.debug("admiral heartbeat") if $DEBUG
22
+ end,
20
23
  post_fork: ->(admiral, captain) do
21
24
  admiral.logger.debug("captain=#{captain.label} post-fork") if $DEBUG
22
25
  end,
@@ -12,8 +12,8 @@ class Navy::Captain < Navy::Rank
12
12
  # list of signals we care about and trap in admiral.
13
13
  QUEUE_SIGS = [ :WINCH, :QUIT, :INT, :TERM, :USR1, :USR2, :HUP, :TTIN, :TTOU ]
14
14
 
15
- attr_accessor :label, :captain_pid, :timeout, :officer_count, :officer_job, :respawn_limit, :respawn_limit_seconds
16
- attr_reader :admiral, :options
15
+ attr_accessor :label, :captain_pid, :officer_count, :officer_job
16
+ attr_reader :admiral, :options
17
17
 
18
18
  def initialize(admiral, label, config, options = {})
19
19
  self.orig_stderr = $stderr.dup
@@ -70,6 +70,7 @@ class Navy::Captain < Navy::Rank
70
70
  # avoid murdering workers after our master process (or the
71
71
  # machine) comes out of suspend/hibernation
72
72
  if (last_check + @timeout) >= (last_check = Time.now)
73
+ heartbeat.call(self) if heartbeat
73
74
  sleep_time = murder_lazy_officers
74
75
  logger.debug("would normally murder lazy officers") if $DEBUG
75
76
  else
@@ -121,12 +122,15 @@ class Navy::Captain < Navy::Rank
121
122
  # Terminates all captains, but does not exit admiral process
122
123
  def stop(graceful = true)
123
124
  before_stop.call(self, graceful) if before_stop
124
- limit = Time.now + timeout
125
- until OFFICERS.empty? || Time.now > limit
125
+ limit = Time.now + patience
126
+ until OFFICERS.empty? || (n = Time.now) > limit
126
127
  kill_each_officer(graceful ? :QUIT : :TERM)
127
128
  sleep(0.1)
128
129
  reap_all_officers
129
130
  end
131
+ if n and n > limit
132
+ logger.debug "captain=#{label} patience exceeded by #{n - limit} seconds (limit #{patience} seconds)" if $DEBUG
133
+ end
130
134
  kill_each_officer(:KILL)
131
135
  after_stop.call(self, graceful) if after_stop
132
136
  end
@@ -13,8 +13,12 @@ class Navy::Captain::Orders < Navy::Orders
13
13
  before_stop: ->(captain, graceful) do
14
14
  captain.logger.debug("captain=#{captain.label} before (#{graceful ? 'graceful' : 'hard'}) stop") if $DEBUG
15
15
  end,
16
+ heartbeat: ->(captain) do
17
+ captain.logger.debug("captain=#{captain.label} heartbeat") if $DEBUG
18
+ end,
16
19
  officer_job: -> { trap(:QUIT) { exit }; trap(:TERM) { exit }; loop { sleep 1 } },
17
20
  officer_count: 0,
21
+ patience: 30,
18
22
  post_fork: ->(captain, officer) do
19
23
  captain.logger.debug("(#{captain.label}) officer=#{officer.number} post-fork") if $DEBUG
20
24
  end,
@@ -26,9 +26,10 @@ class Navy::Orders
26
26
  attr_writer :defaults
27
27
 
28
28
  self.defaults = {
29
- timeout: 60,
30
- logger: Navy.logger,
31
- pid: nil
29
+ logger: Navy.logger,
30
+ patience: 60,
31
+ pid: nil,
32
+ timeout: 60
32
33
  }
33
34
 
34
35
  def self.inherited(base)
@@ -1,10 +1,28 @@
1
1
  class Navy::Rank
2
2
 
3
+ # orders are configuration settings
3
4
  attr_accessor :orders
4
5
 
5
- attr_accessor :before_fork, :after_fork, :before_exec, :post_fork, :before_stop, :after_stop
6
+ ## callbacks ##
7
+ attr_accessor :before_fork,
8
+ :before_stop,
9
+ :after_fork,
10
+ :after_stop,
11
+ :heartbeat,
12
+ :post_fork
13
+
14
+ ## reexec ##
15
+ attr_accessor :reexec_pid
16
+
17
+ ## respawn ##
18
+ attr_accessor :respawn_limit, :respawn_limit_seconds
19
+
20
+ ## stderr/stdout ##
6
21
  attr_reader :stdout_path, :stderr_path
7
- attr_accessor :reexec_pid, :orig_stdout, :orig_stderr, :current_stdout, :current_stderr
22
+ attr_accessor :orig_stdout, :orig_stderr, :current_stdout, :current_stderr
23
+
24
+ ## timeouts ##
25
+ attr_accessor :patience, :timeout
8
26
 
9
27
  def logger
10
28
  (@logger ||= orders[:logger]).tap do |log|
@@ -57,8 +75,6 @@ class Navy::Rank
57
75
  redirect_io($stderr, path)
58
76
  end
59
77
 
60
- attr_accessor :timeout
61
-
62
78
  private
63
79
 
64
80
  # unlinks a PID file at given +path+ if it contains the current PID
@@ -30,6 +30,10 @@ class Navy::Speak
30
30
  set_hook(:before_stop, block_given? ? block : args[0])
31
31
  end
32
32
 
33
+ def heartbeat(*args, &block)
34
+ set_hook(:heartbeat, block_given? ? block : args[0], 1)
35
+ end
36
+
33
37
  def logger(obj)
34
38
  %w(debug info warn error fatal).each do |m|
35
39
  obj.respond_to?(m) and next
@@ -39,6 +43,13 @@ class Navy::Speak
39
43
  orders.set[:logger] = obj
40
44
  end
41
45
 
46
+ def patience(seconds)
47
+ set_int(:patience, seconds, 3)
48
+ # POSIX says 31 days is the smallest allowed maximum timeout for select()
49
+ max = 30 * 60 * 60 * 24
50
+ orders.set[:patience] = seconds > max ? max : seconds
51
+ end
52
+
42
53
  def pid(path); set_path(:pid, path); end
43
54
 
44
55
  def post_fork(*args, &block)
@@ -1,3 +1,3 @@
1
1
  module Navy
2
- VERSION = "1.0.7"
2
+ VERSION = "1.1.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: navy
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.7
4
+ version: 1.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-06 00:00:00.000000000 Z
12
+ date: 2012-03-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: pry
16
- requirement: &70187979402440 !ruby/object:Gem::Requirement
16
+ requirement: &70241876400920 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70187979402440
24
+ version_requirements: *70241876400920
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &70187979401840 !ruby/object:Gem::Requirement
27
+ requirement: &70241876399140 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70187979401840
35
+ version_requirements: *70241876399140
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rspec
38
- requirement: &70187979401100 !ruby/object:Gem::Requirement
38
+ requirement: &70241876397680 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 2.8.0
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70187979401100
46
+ version_requirements: *70241876397680
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: kgio
49
- requirement: &70187979400340 !ruby/object:Gem::Requirement
49
+ requirement: &70241876396780 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,7 +54,7 @@ dependencies:
54
54
  version: '2.6'
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *70187979400340
57
+ version_requirements: *70241876396780
58
58
  description: Ruby daemon inspired by Unicorn.
59
59
  email:
60
60
  - potatosaladx@gmail.com