navy 1.0.7 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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