bluepill 0.0.46 → 0.0.47
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.
- data/.gitignore +4 -1
- data/Gemfile +4 -0
- data/README.md +2 -2
- data/Rakefile +2 -55
- data/bin/bluepill +1 -1
- data/bin/sample_forking_server +53 -0
- data/bluepill.gemspec +21 -81
- data/{lib → examples}/example.rb +24 -24
- data/{lib → examples}/runit_example.rb +4 -3
- data/lib/bluepill.rb +6 -1
- data/lib/bluepill/application.rb +27 -26
- data/lib/bluepill/application/client.rb +2 -1
- data/lib/bluepill/application/server.rb +4 -3
- data/lib/bluepill/condition_watch.rb +25 -30
- data/lib/bluepill/controller.rb +13 -12
- data/lib/bluepill/dsl.rb +4 -151
- data/lib/bluepill/dsl/app_proxy.rb +25 -0
- data/lib/bluepill/dsl/process_factory.rb +87 -0
- data/lib/bluepill/dsl/process_proxy.rb +36 -0
- data/lib/bluepill/group.rb +9 -8
- data/lib/bluepill/logger.rb +10 -9
- data/lib/bluepill/process.rb +90 -97
- data/lib/bluepill/process_conditions.rb +2 -1
- data/lib/bluepill/process_conditions/always_true.rb +3 -2
- data/lib/bluepill/process_conditions/cpu_usage.rb +3 -2
- data/lib/bluepill/process_conditions/http.rb +1 -0
- data/lib/bluepill/process_conditions/mem_usage.rb +5 -4
- data/lib/bluepill/process_conditions/process_condition.rb +5 -4
- data/lib/bluepill/process_statistics.rb +7 -8
- data/lib/bluepill/socket.rb +6 -6
- data/lib/bluepill/system.rb +43 -42
- data/lib/bluepill/trigger.rb +10 -19
- data/lib/bluepill/triggers/flapping.rb +13 -14
- data/lib/bluepill/util/rotational_array.rb +14 -66
- data/lib/bluepill/version.rb +2 -1
- metadata +53 -46
- data/VERSION +0 -1
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module Bluepill
|
3
|
+
class ProcessProxy
|
4
|
+
attr_reader :attributes, :watches, :name
|
5
|
+
def initialize(process_name, attributes, process_block)
|
6
|
+
@name = process_name
|
7
|
+
@attributes = attributes
|
8
|
+
@watches = {}
|
9
|
+
|
10
|
+
process_block.call(self)
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_missing(name, *args)
|
14
|
+
if args.size == 1 && name.to_s =~ /^(.*)=$/
|
15
|
+
@attributes[$1.to_sym] = args.first
|
16
|
+
elsif args.empty? && @attributes.key?(name.to_sym)
|
17
|
+
@attributes[name.to_sym]
|
18
|
+
else
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def checks(name, options = {})
|
24
|
+
@watches[name] = options
|
25
|
+
end
|
26
|
+
|
27
|
+
def monitor_children(&child_process_block)
|
28
|
+
@attributes[:monitor_children] = true
|
29
|
+
@attributes[:child_process_block] = child_process_block
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_process
|
33
|
+
Process.new(@name, @watches, @attributes)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/bluepill/group.rb
CHANGED
@@ -1,25 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
1
2
|
module Bluepill
|
2
3
|
class Group
|
3
4
|
attr_accessor :name, :processes, :logger
|
4
5
|
attr_accessor :process_logger
|
5
|
-
|
6
|
+
|
6
7
|
def initialize(name, options = {})
|
7
8
|
self.name = name
|
8
9
|
self.processes = []
|
9
10
|
self.logger = options[:logger]
|
10
11
|
end
|
11
|
-
|
12
|
+
|
12
13
|
def add_process(process)
|
13
14
|
process.logger = self.logger.prefix_with(process.name)
|
14
15
|
self.processes << process
|
15
16
|
end
|
16
|
-
|
17
|
+
|
17
18
|
def tick
|
18
19
|
self.processes.each do |process|
|
19
20
|
process.tick
|
20
21
|
end
|
21
22
|
end
|
22
|
-
|
23
|
+
|
23
24
|
def determine_initial_state
|
24
25
|
self.processes.each do |process|
|
25
26
|
process.determine_initial_state
|
@@ -39,16 +40,16 @@ module Bluepill
|
|
39
40
|
end
|
40
41
|
threads.each { |t| t.join }
|
41
42
|
affected
|
42
|
-
end
|
43
|
+
end
|
43
44
|
END
|
44
45
|
end
|
45
|
-
|
46
|
+
|
46
47
|
def status(process_name = nil)
|
47
48
|
lines = []
|
48
49
|
if process_name.nil?
|
49
50
|
prefix = self.name ? " " : ""
|
50
51
|
lines << "#{self.name}:" if self.name
|
51
|
-
|
52
|
+
|
52
53
|
self.processes.each do |process|
|
53
54
|
lines << "%s%s(pid:%s): %s" % [prefix, process.name, process.actual_pid, process.state]
|
54
55
|
if process.monitor_children?
|
@@ -66,6 +67,6 @@ module Bluepill
|
|
66
67
|
end
|
67
68
|
lines << ""
|
68
69
|
end
|
69
|
-
|
70
|
+
|
70
71
|
end
|
71
72
|
end
|
data/lib/bluepill/logger.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module Bluepill
|
2
3
|
class Logger
|
3
4
|
LOG_METHODS = [:emerg, :alert, :crit, :err, :warning, :notice, :info, :debug]
|
4
|
-
|
5
|
+
|
5
6
|
def initialize(options = {})
|
6
7
|
@options = options
|
7
8
|
@logger = options[:logger] || self.create_logger
|
@@ -9,7 +10,7 @@ module Bluepill
|
|
9
10
|
@stdout = options[:stdout]
|
10
11
|
@prefixes = {}
|
11
12
|
end
|
12
|
-
|
13
|
+
|
13
14
|
LOG_METHODS.each do |method|
|
14
15
|
eval <<-END
|
15
16
|
def #{method}(msg, prefix = [])
|
@@ -26,11 +27,11 @@ module Bluepill
|
|
26
27
|
end
|
27
28
|
END
|
28
29
|
end
|
29
|
-
|
30
|
+
|
30
31
|
def prefix_with(prefix)
|
31
32
|
@prefixes[prefix] ||= self.class.new(:logger => self, :prefix => prefix)
|
32
33
|
end
|
33
|
-
|
34
|
+
|
34
35
|
def reopen
|
35
36
|
if @logger.is_a?(self.class)
|
36
37
|
@logger.reopen
|
@@ -38,7 +39,7 @@ module Bluepill
|
|
38
39
|
@logger = create_logger
|
39
40
|
end
|
40
41
|
end
|
41
|
-
|
42
|
+
|
42
43
|
protected
|
43
44
|
def create_logger
|
44
45
|
if @options[:log_file]
|
@@ -50,13 +51,13 @@ module Bluepill
|
|
50
51
|
end
|
51
52
|
|
52
53
|
class LoggerAdapter < ::Logger
|
53
|
-
LOGGER_EQUIVALENTS =
|
54
|
+
LOGGER_EQUIVALENTS =
|
54
55
|
{:debug => :debug, :err => :error, :warning => :warn, :info => :info, :emerg => :fatal, :alert => :warn, :crit => :fatal, :notice => :info}
|
55
|
-
|
56
|
+
|
56
57
|
LOG_METHODS.each do |method|
|
57
58
|
next if method == LOGGER_EQUIVALENTS[method]
|
58
59
|
alias_method method, LOGGER_EQUIVALENTS[method]
|
59
60
|
end
|
60
|
-
end
|
61
|
+
end
|
61
62
|
end
|
62
63
|
end
|
data/lib/bluepill/process.rb
CHANGED
@@ -1,37 +1,38 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
1
2
|
require "state_machine"
|
2
3
|
require "daemons"
|
3
4
|
|
4
5
|
module Bluepill
|
5
6
|
class Process
|
6
7
|
CONFIGURABLE_ATTRIBUTES = [
|
7
|
-
:start_command,
|
8
|
-
:stop_command,
|
9
|
-
:restart_command,
|
10
|
-
|
8
|
+
:start_command,
|
9
|
+
:stop_command,
|
10
|
+
:restart_command,
|
11
|
+
|
11
12
|
:stdout,
|
12
13
|
:stderr,
|
13
14
|
:stdin,
|
14
|
-
|
15
|
-
:daemonize,
|
16
|
-
:pid_file,
|
15
|
+
|
16
|
+
:daemonize,
|
17
|
+
:pid_file,
|
17
18
|
:working_dir,
|
18
19
|
:environment,
|
19
|
-
|
20
|
-
:start_grace_time,
|
21
|
-
:stop_grace_time,
|
20
|
+
|
21
|
+
:start_grace_time,
|
22
|
+
:stop_grace_time,
|
22
23
|
:restart_grace_time,
|
23
|
-
|
24
|
+
|
24
25
|
:uid,
|
25
26
|
:gid,
|
26
|
-
|
27
|
+
|
27
28
|
:monitor_children,
|
28
|
-
:
|
29
|
+
:child_process_factory
|
29
30
|
]
|
30
|
-
|
31
|
-
attr_accessor :name, :watches, :triggers, :logger, :skip_ticks_until
|
31
|
+
|
32
|
+
attr_accessor :name, :watches, :triggers, :logger, :skip_ticks_until, :process_running
|
32
33
|
attr_accessor *CONFIGURABLE_ATTRIBUTES
|
33
34
|
attr_reader :children, :statistics
|
34
|
-
|
35
|
+
|
35
36
|
state_machine :initial => :unmonitored do
|
36
37
|
# These are the idle states, i.e. only an event (either external or internal) will trigger a transition.
|
37
38
|
# The distinction between down and unmonitored is that down
|
@@ -47,15 +48,15 @@ module Bluepill
|
|
47
48
|
|
48
49
|
transition :up => :up, :if => :process_running?
|
49
50
|
transition :up => :down, :unless => :process_running?
|
50
|
-
|
51
|
+
|
51
52
|
# The process failed to die after entering the stopping state. Change the state to reflect
|
52
53
|
# reality.
|
53
|
-
transition :stopping => :up, :if => :process_running?
|
54
|
+
transition :stopping => :up, :if => :process_running?
|
54
55
|
transition :stopping => :down, :unless => :process_running?
|
55
|
-
|
56
|
+
|
56
57
|
transition :down => :up, :if => :process_running?
|
57
58
|
transition :down => :starting, :unless => :process_running?
|
58
|
-
|
59
|
+
|
59
60
|
transition :restarting => :up, :if => :process_running?
|
60
61
|
transition :restarting => :down, :unless => :process_running?
|
61
62
|
end
|
@@ -84,25 +85,34 @@ module Bluepill
|
|
84
85
|
|
85
86
|
after_transition any => any, :do => :record_transition
|
86
87
|
end
|
87
|
-
|
88
|
-
def initialize(process_name, options = {})
|
88
|
+
|
89
|
+
def initialize(process_name, checks, options = {})
|
89
90
|
@name = process_name
|
90
91
|
@event_mutex = Monitor.new
|
91
|
-
@transition_history = Util::RotationalArray.new(10)
|
92
92
|
@watches = []
|
93
93
|
@triggers = []
|
94
94
|
@children = []
|
95
95
|
@statistics = ProcessStatistics.new
|
96
|
-
|
96
|
+
@actual_pid = options[:actual_pid]
|
97
|
+
self.logger = options[:logger]
|
98
|
+
|
99
|
+
checks.each do |name, opts|
|
100
|
+
if Trigger[name]
|
101
|
+
self.add_trigger(name, opts)
|
102
|
+
else
|
103
|
+
self.add_watch(name, opts)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
97
107
|
# These defaults are overriden below if it's configured to be something else.
|
98
108
|
@monitor_children = false
|
99
109
|
@start_grace_time = @stop_grace_time = @restart_grace_time = 3
|
100
110
|
@environment = {}
|
101
|
-
|
111
|
+
|
102
112
|
CONFIGURABLE_ATTRIBUTES.each do |attribute_name|
|
103
113
|
self.send("#{attribute_name}=", options[attribute_name]) if options.has_key?(attribute_name)
|
104
114
|
end
|
105
|
-
|
115
|
+
|
106
116
|
# Let state_machine do its initialization stuff
|
107
117
|
super() # no arguments intentional
|
108
118
|
end
|
@@ -119,20 +129,20 @@ module Bluepill
|
|
119
129
|
|
120
130
|
if self.up?
|
121
131
|
self.run_watches
|
122
|
-
|
132
|
+
|
123
133
|
if self.monitor_children?
|
124
134
|
refresh_children!
|
125
135
|
children.each {|child| child.tick}
|
126
136
|
end
|
127
137
|
end
|
128
138
|
end
|
129
|
-
|
139
|
+
|
130
140
|
def logger=(logger)
|
131
141
|
@logger = logger
|
132
142
|
self.watches.each {|w| w.logger = logger }
|
133
143
|
self.triggers.each {|t| t.logger = logger }
|
134
144
|
end
|
135
|
-
|
145
|
+
|
136
146
|
# State machine methods
|
137
147
|
def dispatch!(event, reason = nil)
|
138
148
|
@event_mutex.synchronize do
|
@@ -140,14 +150,14 @@ module Bluepill
|
|
140
150
|
self.send("#{event}")
|
141
151
|
end
|
142
152
|
end
|
143
|
-
|
153
|
+
|
144
154
|
def record_transition(transition)
|
145
155
|
unless transition.loopback?
|
146
156
|
@transitioned = true
|
147
|
-
|
157
|
+
|
148
158
|
# When a process changes state, we should clear the memory of all the watches
|
149
159
|
self.watches.each { |w| w.clear_history! }
|
150
|
-
|
160
|
+
|
151
161
|
# Also, when a process changes state, we should re-populate its child list
|
152
162
|
if self.monitor_children?
|
153
163
|
self.logger.warning "Clearing child list"
|
@@ -156,16 +166,16 @@ module Bluepill
|
|
156
166
|
logger.info "Going from #{transition.from_name} => #{transition.to_name}"
|
157
167
|
end
|
158
168
|
end
|
159
|
-
|
169
|
+
|
160
170
|
def notify_triggers(transition)
|
161
171
|
self.triggers.each {|trigger| trigger.notify(transition)}
|
162
172
|
end
|
163
|
-
|
173
|
+
|
164
174
|
# Watch related methods
|
165
175
|
def add_watch(name, options = {})
|
166
176
|
self.watches << ConditionWatch.new(name, options.merge(:logger => self.logger))
|
167
177
|
end
|
168
|
-
|
178
|
+
|
169
179
|
def add_trigger(name, options = {})
|
170
180
|
self.triggers << Trigger[name].new(self, options.merge(:logger => self.logger))
|
171
181
|
end
|
@@ -176,9 +186,9 @@ module Bluepill
|
|
176
186
|
threads = self.watches.collect do |watch|
|
177
187
|
[watch, Thread.new { Thread.current[:events] = watch.run(self.actual_pid, now) }]
|
178
188
|
end
|
179
|
-
|
189
|
+
|
180
190
|
@transitioned = false
|
181
|
-
|
191
|
+
|
182
192
|
threads.inject([]) do |events, (watch, thread)|
|
183
193
|
thread.join
|
184
194
|
if thread[:events].size > 0
|
@@ -193,7 +203,7 @@ module Bluepill
|
|
193
203
|
self.dispatch!(event, reason)
|
194
204
|
end
|
195
205
|
end
|
196
|
-
|
206
|
+
|
197
207
|
def determine_initial_state
|
198
208
|
if self.process_running?(true)
|
199
209
|
self.state = 'up'
|
@@ -202,7 +212,7 @@ module Bluepill
|
|
202
212
|
self.state = 'down'
|
203
213
|
end
|
204
214
|
end
|
205
|
-
|
215
|
+
|
206
216
|
def handle_user_command(cmd)
|
207
217
|
case cmd
|
208
218
|
when "start"
|
@@ -223,67 +233,67 @@ module Bluepill
|
|
223
233
|
dispatch!(:unmonitor, "user initiated")
|
224
234
|
end
|
225
235
|
end
|
226
|
-
|
236
|
+
|
227
237
|
# System Process Methods
|
228
238
|
def process_running?(force = false)
|
229
239
|
@process_running = nil if force # clear existing state if forced
|
230
|
-
|
240
|
+
|
231
241
|
@process_running ||= signal_process(0)
|
232
242
|
# the process isn't running, so we should clear the PID
|
233
243
|
self.clear_pid unless @process_running
|
234
244
|
@process_running
|
235
245
|
end
|
236
|
-
|
246
|
+
|
237
247
|
def start_process
|
238
248
|
logger.warning "Executing start command: #{start_command}"
|
239
|
-
|
249
|
+
|
240
250
|
if self.daemonize?
|
241
251
|
System.daemonize(start_command, self.system_command_options)
|
242
|
-
|
252
|
+
|
243
253
|
else
|
244
254
|
# This is a self-daemonizing process
|
245
255
|
with_timeout(start_grace_time) do
|
246
256
|
result = System.execute_blocking(start_command, self.system_command_options)
|
247
|
-
|
257
|
+
|
248
258
|
unless result[:exit_code].zero?
|
249
259
|
logger.warning "Start command execution returned non-zero exit code:"
|
250
260
|
logger.warning result.inspect
|
251
|
-
end
|
261
|
+
end
|
252
262
|
end
|
253
263
|
end
|
254
|
-
|
264
|
+
|
255
265
|
self.skip_ticks_for(start_grace_time)
|
256
266
|
end
|
257
|
-
|
258
|
-
def stop_process
|
267
|
+
|
268
|
+
def stop_process
|
259
269
|
if stop_command
|
260
270
|
cmd = self.prepare_command(stop_command)
|
261
271
|
logger.warning "Executing stop command: #{cmd}"
|
262
|
-
|
272
|
+
|
263
273
|
with_timeout(stop_grace_time) do
|
264
274
|
result = System.execute_blocking(cmd, self.system_command_options)
|
265
|
-
|
275
|
+
|
266
276
|
unless result[:exit_code].zero?
|
267
277
|
logger.warning "Stop command execution returned non-zero exit code:"
|
268
278
|
logger.warning result.inspect
|
269
279
|
end
|
270
280
|
end
|
271
|
-
|
281
|
+
|
272
282
|
else
|
273
283
|
logger.warning "Executing default stop command. Sending TERM signal to #{actual_pid}"
|
274
284
|
signal_process("TERM")
|
275
285
|
end
|
276
286
|
self.unlink_pid # TODO: we only write the pid file if we daemonize, should we only unlink it if we daemonize?
|
277
|
-
|
287
|
+
|
278
288
|
self.skip_ticks_for(stop_grace_time)
|
279
289
|
end
|
280
|
-
|
290
|
+
|
281
291
|
def restart_process
|
282
292
|
if restart_command
|
283
293
|
cmd = self.prepare_command(restart_command)
|
284
|
-
|
294
|
+
|
285
295
|
logger.warning "Executing restart command: #{cmd}"
|
286
|
-
|
296
|
+
|
287
297
|
with_timeout(restart_grace_time) do
|
288
298
|
result = System.execute_blocking(cmd, self.system_command_options)
|
289
299
|
|
@@ -292,7 +302,7 @@ module Bluepill
|
|
292
302
|
logger.warning result.inspect
|
293
303
|
end
|
294
304
|
end
|
295
|
-
|
305
|
+
|
296
306
|
self.skip_ticks_for(restart_grace_time)
|
297
307
|
else
|
298
308
|
logger.warning "No restart_command specified. Must stop and start to restart"
|
@@ -300,22 +310,22 @@ module Bluepill
|
|
300
310
|
# the tick will bring it back.
|
301
311
|
end
|
302
312
|
end
|
303
|
-
|
313
|
+
|
304
314
|
def daemonize?
|
305
315
|
!!self.daemonize
|
306
316
|
end
|
307
|
-
|
317
|
+
|
308
318
|
def monitor_children?
|
309
319
|
!!self.monitor_children
|
310
320
|
end
|
311
|
-
|
321
|
+
|
312
322
|
def signal_process(code)
|
313
323
|
::Process.kill(code, actual_pid)
|
314
324
|
true
|
315
325
|
rescue
|
316
326
|
false
|
317
327
|
end
|
318
|
-
|
328
|
+
|
319
329
|
def actual_pid
|
320
330
|
@actual_pid ||= begin
|
321
331
|
if pid_file
|
@@ -329,77 +339,60 @@ module Bluepill
|
|
329
339
|
end
|
330
340
|
end
|
331
341
|
end
|
332
|
-
|
342
|
+
|
333
343
|
def actual_pid=(pid)
|
334
344
|
@actual_pid = pid
|
335
345
|
end
|
336
|
-
|
346
|
+
|
337
347
|
def clear_pid
|
338
348
|
@actual_pid = nil
|
339
349
|
end
|
340
|
-
|
350
|
+
|
341
351
|
def unlink_pid
|
342
352
|
File.unlink(pid_file) if pid_file && File.exists?(pid_file)
|
343
353
|
rescue Errno::ENOENT
|
344
354
|
end
|
345
|
-
|
355
|
+
|
346
356
|
# Internal State Methods
|
347
357
|
def skip_ticks_for(seconds)
|
348
358
|
# TODO: should this be addative or longest wins?
|
349
359
|
# i.e. if two calls for skip_ticks_for come in for 5 and 10, should it skip for 10 or 15?
|
350
360
|
self.skip_ticks_until = (self.skip_ticks_until || Time.now.to_i) + seconds.to_i
|
351
361
|
end
|
352
|
-
|
362
|
+
|
353
363
|
def skipping_ticks?
|
354
364
|
self.skip_ticks_until && self.skip_ticks_until > Time.now.to_i
|
355
365
|
end
|
356
|
-
|
366
|
+
|
357
367
|
def refresh_children!
|
358
368
|
# First prune the list of dead children
|
359
369
|
@children.delete_if {|child| !child.process_running?(true) }
|
360
|
-
|
370
|
+
|
361
371
|
# Add new found children to the list
|
362
372
|
new_children_pids = System.get_children(self.actual_pid) - @children.map {|child| child.actual_pid}
|
363
|
-
|
373
|
+
|
364
374
|
unless new_children_pids.empty?
|
365
375
|
logger.info "Existing children: #{@children.collect{|c| c.actual_pid}.join(",")}. Got new children: #{new_children_pids.inspect} for #{actual_pid}"
|
366
376
|
end
|
367
|
-
|
377
|
+
|
368
378
|
# Construct a new process wrapper for each new found children
|
369
379
|
new_children_pids.each do |child_pid|
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
child
|
374
|
-
child.logger = self.logger.prefix_with(child.name)
|
375
|
-
|
376
|
-
child.initialize_state_machines
|
377
|
-
child.state = "up"
|
378
|
-
|
380
|
+
name = "<child(pid:#{child_pid})>"
|
381
|
+
logger = self.logger.prefix_with(name)
|
382
|
+
|
383
|
+
child = self.child_process_factory.create_child_process(name, child_pid, logger)
|
379
384
|
@children << child
|
380
385
|
end
|
381
386
|
end
|
382
387
|
|
383
|
-
def deep_copy
|
384
|
-
# TODO: This is a kludge. Ideally, process templates
|
385
|
-
# would be facotries, and not a template object.
|
386
|
-
mutex, triggers, @event_mutex, @triggers = @event_mutex, @triggers, nil, nil
|
387
|
-
clone = Marshal.load(Marshal.dump(self))
|
388
|
-
clone.instance_variable_set("@event_mutex", Monitor.new)
|
389
|
-
clone.instance_variable_set("@triggers", triggers.collect{ |t| t.deep_copy })
|
390
|
-
@event_mutex = mutex
|
391
|
-
@triggers = triggers
|
392
|
-
clone
|
393
|
-
end
|
394
|
-
|
395
388
|
def prepare_command(command)
|
396
389
|
command.to_s.gsub("{{PID}}", actual_pid.to_s)
|
397
390
|
end
|
398
|
-
|
391
|
+
|
399
392
|
def system_command_options
|
400
393
|
{
|
401
|
-
:uid => self.uid,
|
402
|
-
:gid => self.gid,
|
394
|
+
:uid => self.uid,
|
395
|
+
:gid => self.gid,
|
403
396
|
:working_dir => self.working_dir,
|
404
397
|
:environment => self.environment,
|
405
398
|
:pid_file => self.pid_file,
|
@@ -409,10 +402,10 @@ module Bluepill
|
|
409
402
|
:stderr => self.stderr
|
410
403
|
}
|
411
404
|
end
|
412
|
-
|
405
|
+
|
413
406
|
def with_timeout(secs, &blk)
|
414
407
|
Timeout.timeout(secs.to_f, &blk)
|
415
|
-
|
408
|
+
|
416
409
|
rescue Timeout::Error
|
417
410
|
logger.err "Execution is taking longer than expected. Unmonitoring."
|
418
411
|
logger.err "Did you forget to tell bluepill to daemonize this process?"
|
@@ -420,4 +413,4 @@ module Bluepill
|
|
420
413
|
end
|
421
414
|
end
|
422
415
|
end
|
423
|
-
|
416
|
+
|