cognizant 0.0.2 → 0.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 +7 -0
- data/.gitignore +1 -0
- data/.travis.yml +17 -0
- data/Gemfile +4 -1
- data/{LICENSE → License.md} +4 -2
- data/Rakefile +5 -0
- data/Readme.md +95 -0
- data/bin/cognizant +76 -122
- data/bin/cognizantd +28 -61
- data/cognizant.gemspec +8 -4
- data/examples/apps/redis-server.cz +42 -0
- data/examples/apps/redis-server.yml +29 -0
- data/examples/apps/redis-server_dsl.cz +54 -0
- data/examples/apps/resque.cz +17 -0
- data/examples/apps/thin.cz +32 -0
- data/examples/apps/thin.yml +48 -0
- data/examples/cognizantd.yml +18 -47
- data/features/child_process.feature +62 -0
- data/features/commands.feature +65 -0
- data/features/cpu_usage.feature +45 -0
- data/features/daemon.feature +12 -0
- data/features/flapping.feature +39 -0
- data/features/memory_usage.feature +45 -0
- data/features/shell.feature +30 -0
- data/features/step_definitions/common_steps.rb +14 -0
- data/features/step_definitions/daemon_steps.rb +25 -0
- data/features/step_definitions/shell_steps.rb +96 -0
- data/features/support/env.rb +54 -0
- data/lib/cognizant.rb +1 -5
- data/lib/cognizant/application.rb +122 -0
- data/lib/cognizant/application/dsl_proxy.rb +23 -0
- data/lib/cognizant/client.rb +61 -0
- data/lib/cognizant/commands.rb +164 -0
- data/lib/cognizant/commands/actions.rb +30 -0
- data/lib/cognizant/commands/help.rb +10 -0
- data/lib/cognizant/commands/load.rb +10 -0
- data/lib/cognizant/commands/shutdown.rb +7 -0
- data/lib/cognizant/commands/status.rb +11 -0
- data/lib/cognizant/commands/use.rb +15 -0
- data/lib/cognizant/controller.rb +17 -0
- data/lib/cognizant/daemon.rb +279 -0
- data/lib/cognizant/interface.rb +17 -0
- data/lib/cognizant/log.rb +25 -0
- data/lib/cognizant/process.rb +138 -94
- data/lib/cognizant/process/actions.rb +30 -41
- data/lib/cognizant/process/actions/restart.rb +73 -17
- data/lib/cognizant/process/actions/start.rb +35 -12
- data/lib/cognizant/process/actions/stop.rb +38 -17
- data/lib/cognizant/process/attributes.rb +41 -10
- data/lib/cognizant/process/children.rb +36 -0
- data/lib/cognizant/process/{condition_check.rb → condition_delegate.rb} +11 -13
- data/lib/cognizant/process/conditions.rb +7 -4
- data/lib/cognizant/process/conditions/cpu_usage.rb +5 -6
- data/lib/cognizant/process/conditions/memory_usage.rb +2 -6
- data/lib/cognizant/process/dsl_proxy.rb +23 -0
- data/lib/cognizant/process/execution.rb +16 -9
- data/lib/cognizant/process/pid.rb +16 -6
- data/lib/cognizant/process/status.rb +14 -2
- data/lib/cognizant/process/trigger_delegate.rb +57 -0
- data/lib/cognizant/process/triggers.rb +19 -0
- data/lib/cognizant/process/triggers/flapping.rb +68 -0
- data/lib/cognizant/process/triggers/transition.rb +22 -0
- data/lib/cognizant/process/triggers/trigger.rb +15 -0
- data/lib/cognizant/shell.rb +142 -0
- data/lib/cognizant/system.rb +16 -0
- data/lib/cognizant/system/ps.rb +1 -1
- data/lib/cognizant/system/signal.rb +2 -2
- data/lib/cognizant/util/dsl_proxy_methods_handler.rb +25 -0
- data/lib/cognizant/util/fixnum_percent.rb +5 -0
- data/lib/cognizant/util/transform_hash_keys.rb +33 -0
- data/lib/cognizant/validations.rb +142 -142
- data/lib/cognizant/version.rb +1 -1
- metadata +131 -71
- data/README.md +0 -221
- data/examples/redis-server.rb +0 -28
- data/examples/resque.rb +0 -10
- data/images/logo-small.png +0 -0
- data/images/logo.png +0 -0
- data/images/logo.pxm +0 -0
- data/lib/cognizant/logging.rb +0 -33
- data/lib/cognizant/process/conditions/flapping.rb +0 -57
- data/lib/cognizant/process/conditions/trigger_condition.rb +0 -52
- data/lib/cognizant/server.rb +0 -14
- data/lib/cognizant/server/commands.rb +0 -80
- data/lib/cognizant/server/daemon.rb +0 -277
- data/lib/cognizant/server/interface.rb +0 -86
- data/lib/cognizant/util/symbolize_hash_keys.rb +0 -19
@@ -0,0 +1,17 @@
|
|
1
|
+
require "eventmachine"
|
2
|
+
|
3
|
+
require "cognizant/commands"
|
4
|
+
|
5
|
+
module Cognizant
|
6
|
+
class Interface < EventMachine::Connection
|
7
|
+
def post_init
|
8
|
+
end
|
9
|
+
|
10
|
+
def receive_data(args)
|
11
|
+
Cognizant::Commands.process_command(self, args)
|
12
|
+
end
|
13
|
+
|
14
|
+
def unbind
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "logging"
|
2
|
+
|
3
|
+
module Cognizant
|
4
|
+
module Log
|
5
|
+
def self.logger
|
6
|
+
Logging.logger
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.[](name)
|
10
|
+
self.logger[name]
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.stdout
|
14
|
+
Logging.appenders.stdout
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.syslog(*args)
|
18
|
+
Logging.appenders.syslog(*args)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.file(*args)
|
22
|
+
Logging.appenders.file(*args)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/cognizant/process.rb
CHANGED
@@ -3,13 +3,18 @@ require "thread"
|
|
3
3
|
|
4
4
|
require "state_machine"
|
5
5
|
|
6
|
+
require "cognizant/process/dsl_proxy"
|
6
7
|
require "cognizant/process/pid"
|
7
8
|
require "cognizant/process/status"
|
8
9
|
require "cognizant/process/execution"
|
9
10
|
require "cognizant/process/attributes"
|
10
11
|
require "cognizant/process/actions"
|
11
|
-
require "cognizant/process/
|
12
|
-
require "cognizant/
|
12
|
+
require "cognizant/process/conditions"
|
13
|
+
require "cognizant/process/condition_delegate"
|
14
|
+
require "cognizant/process/triggers"
|
15
|
+
require "cognizant/process/trigger_delegate"
|
16
|
+
require "cognizant/process/children"
|
17
|
+
require "cognizant/util/transform_hash_keys"
|
13
18
|
|
14
19
|
module Cognizant
|
15
20
|
class Process
|
@@ -18,6 +23,7 @@ module Cognizant
|
|
18
23
|
include Cognizant::Process::Execution
|
19
24
|
include Cognizant::Process::Attributes
|
20
25
|
include Cognizant::Process::Actions
|
26
|
+
include Cognizant::Process::Children
|
21
27
|
|
22
28
|
state_machine :initial => :unmonitored do
|
23
29
|
# These are the idle states, i.e. only an event (either external or internal) will trigger a transition.
|
@@ -65,40 +71,69 @@ module Cognizant
|
|
65
71
|
transition any => :unmonitored
|
66
72
|
end
|
67
73
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
before_transition any => :
|
72
|
-
after_transition
|
74
|
+
before_transition any => :starting, :do => lambda { |p| p.autostart = true }
|
75
|
+
after_transition any => :starting, :do => :start_process
|
76
|
+
|
77
|
+
before_transition any => :stopping, :do => lambda { |p| p.autostart = false }
|
78
|
+
after_transition :running => :stopping, :do => :stop_process
|
79
|
+
|
80
|
+
before_transition any => :restarting, :do => lambda { |p| p.autostart = true }
|
81
|
+
after_transition any => :restarting, :do => :restart_process
|
82
|
+
|
83
|
+
before_transition any => :unmonitored, :do => lambda { |p| p.autostart = false }
|
73
84
|
|
74
85
|
before_transition any => any, :do => :notify_triggers
|
75
86
|
after_transition any => any, :do => :record_transition
|
76
87
|
end
|
77
88
|
|
78
|
-
def initialize(process_name = nil,
|
89
|
+
def initialize(process_name = nil, attributes = {}, &block)
|
90
|
+
reset!
|
91
|
+
|
92
|
+
@name = process_name.to_s if process_name
|
93
|
+
|
94
|
+
set_attributes(attributes)
|
95
|
+
|
96
|
+
handle_initialize_block(&block) if block
|
97
|
+
|
98
|
+
raise "Process name is missing. Aborting." unless self.name
|
99
|
+
Log[self].info "Loading process #{self.name}..."
|
100
|
+
|
101
|
+
# Let state_machine initialize as well.
|
102
|
+
initialize_state_machines
|
103
|
+
end
|
104
|
+
|
105
|
+
def handle_initialize_block(&block)
|
106
|
+
if block.arity == 0
|
107
|
+
attributes = Cognizant::Process::DSLProxy.new(self, &block).attributes
|
108
|
+
set_attributes(attributes)
|
109
|
+
else
|
110
|
+
instance_exec(self, &block)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def reset!
|
115
|
+
reset_attributes!
|
116
|
+
|
117
|
+
@application = nil
|
79
118
|
@ticks_to_skip = 0
|
80
|
-
@
|
119
|
+
@conditions = []
|
81
120
|
@triggers = []
|
121
|
+
@children = []
|
82
122
|
@action_mutex = Monitor.new
|
83
|
-
|
84
|
-
|
85
|
-
self.autostart = true # Default.
|
86
|
-
|
87
|
-
if options.has_key?(:checks) and options[:checks].kind_of?(Hash)
|
88
|
-
options[:checks].each do |condition_name, args|
|
89
|
-
self.check(condition_name, args)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
options.delete(:checks)
|
123
|
+
@monitor_children = false
|
124
|
+
end
|
93
125
|
|
94
|
-
|
95
|
-
|
126
|
+
def check(check_name, options, &block)
|
127
|
+
if klass = Cognizant::Process::Conditions[check_name]
|
128
|
+
@conditions << ConditionDelegate.new(check_name, options.deep_symbolize_keys!, &block)
|
129
|
+
elsif klass = Cognizant::Process::Triggers[check_name]
|
130
|
+
@triggers << TriggerDelegate.new(check_name, self, options.deep_symbolize_keys!, &block)
|
96
131
|
end
|
132
|
+
end
|
97
133
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
super
|
134
|
+
def monitor_children(child_process_attributes = {}, &child_process_block)
|
135
|
+
@monitor_children = true
|
136
|
+
@child_process_attributes, @child_process_block = child_process_attributes, child_process_block
|
102
137
|
end
|
103
138
|
|
104
139
|
def tick
|
@@ -108,18 +143,28 @@ module Cognizant
|
|
108
143
|
# Invoke the state_machine event.
|
109
144
|
super
|
110
145
|
|
111
|
-
|
146
|
+
if self.running? # State method.
|
147
|
+
run_conditions
|
148
|
+
|
149
|
+
if @monitor_children
|
150
|
+
refresh_children!
|
151
|
+
@children.each(&:tick)
|
152
|
+
end
|
153
|
+
end
|
112
154
|
end
|
113
155
|
|
114
|
-
def
|
115
|
-
|
116
|
-
|
117
|
-
|
156
|
+
def skip_ticks_for(skips)
|
157
|
+
# Accept negative skips with the result being >= 0.
|
158
|
+
# +1 so that we don't have to >= and ensure 0 in #skip_tick?.
|
159
|
+
@ticks_to_skip = [@ticks_to_skip + (skips.to_i + 1), 0].max
|
160
|
+
end
|
118
161
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
162
|
+
def pidfile
|
163
|
+
@pidfile || File.join(@application.pids_dir, @name + '.pid')
|
164
|
+
end
|
165
|
+
|
166
|
+
def logfile
|
167
|
+
@logfile || File.join(@application.logs_dir, @name + '.log')
|
123
168
|
end
|
124
169
|
|
125
170
|
def last_transition_time
|
@@ -127,11 +172,9 @@ module Cognizant
|
|
127
172
|
end
|
128
173
|
|
129
174
|
def handle_user_command(command)
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
@triggers.each { |trigger| trigger.reset! }
|
134
|
-
end
|
175
|
+
# When the user issues a command, reset any
|
176
|
+
# triggers so that scheduled events gets cleared.
|
177
|
+
@triggers.each { |trigger| trigger.reset! }
|
135
178
|
dispatch!(command, "user initiated")
|
136
179
|
end
|
137
180
|
|
@@ -145,72 +188,42 @@ module Cognizant
|
|
145
188
|
end
|
146
189
|
end
|
147
190
|
|
148
|
-
|
149
|
-
klass = Cognizant::Process::Conditions[condition_name]
|
150
|
-
case klass.superclass.name.split("::").last
|
151
|
-
when "TriggerCondition"
|
152
|
-
@triggers << klass.new(self, options.deep_symbolize_keys!)
|
153
|
-
when "PollCondition"
|
154
|
-
@checks << ConditionCheck.new(condition_name, options.deep_symbolize_keys!, &block)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
def notify_triggers(transition)
|
159
|
-
@triggers.each { |trigger| trigger.notify(transition) }
|
160
|
-
end
|
161
|
-
|
162
|
-
def run_checks
|
163
|
-
now = Time.now.to_i
|
191
|
+
private
|
164
192
|
|
165
|
-
|
166
|
-
|
167
|
-
|
193
|
+
def record_transition(transition)
|
194
|
+
unless transition.loopback?
|
195
|
+
@transitioned = true
|
196
|
+
@last_transition_time = Time.now.to_i
|
168
197
|
|
169
|
-
|
198
|
+
# When a process changes state, we should clear the memory of all the conditions.
|
199
|
+
@conditions.each { |condition| condition.clear_history! }
|
200
|
+
Log[self].debug "Changing state of #{name} from #{transition.from_name} => #{transition.to_name}"
|
170
201
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
puts "#{check.condition_name} dispatched: #{thread[:actions].join(',')}"
|
175
|
-
thread[:actions].each do |action|
|
176
|
-
actions << [action, check.to_s]
|
177
|
-
end
|
202
|
+
# And we should re-populate its child list.
|
203
|
+
if @monitor_children
|
204
|
+
@children.clear
|
178
205
|
end
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
self.dispatch!(action, reason)
|
206
|
+
|
207
|
+
# Update the pid from pidfile, since the state of process changed, if the process is managing it's own pidfile.
|
208
|
+
read_pid if @pidfile
|
183
209
|
end
|
184
210
|
end
|
185
211
|
|
186
|
-
def
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
@process_running
|
191
|
-
elsif self.ping_command and run(self.ping_command).succeeded?
|
192
|
-
true
|
193
|
-
elsif pid_running?
|
194
|
-
true
|
195
|
-
else
|
196
|
-
false
|
212
|
+
def set_attributes(attributes)
|
213
|
+
if attributes.has_key?(:checks) and attributes[:checks].kind_of?(Hash)
|
214
|
+
attributes[:checks].each do |check_name, args, &block|
|
215
|
+
check(check_name, args, &block)
|
197
216
|
end
|
198
217
|
end
|
199
|
-
|
200
|
-
|
201
|
-
def pidfile
|
202
|
-
@pidfile = @pidfile || File.join(Cognizant::Server.daemon.pids_dir, self.name + '.pid')
|
203
|
-
end
|
218
|
+
attributes.delete(:checks)
|
204
219
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
private
|
220
|
+
if attributes.has_key?(:monitor_children) and attributes[:monitor_children].kind_of?(Hash)
|
221
|
+
monitor_children(attributes[:monitor_children])
|
222
|
+
end
|
210
223
|
|
211
|
-
|
212
|
-
|
213
|
-
|
224
|
+
attributes.each do |attribute_name, value|
|
225
|
+
self.send("#{attribute_name}=", value) if self.respond_to?("#{attribute_name}=")
|
226
|
+
end
|
214
227
|
end
|
215
228
|
|
216
229
|
def skip_tick?
|
@@ -225,5 +238,36 @@ module Cognizant
|
|
225
238
|
end
|
226
239
|
execute(command, options.merge(action_overrides))
|
227
240
|
end
|
241
|
+
|
242
|
+
def run_conditions
|
243
|
+
now = Time.now.to_i
|
244
|
+
|
245
|
+
threads = @conditions.collect do |condition|
|
246
|
+
[condition, Thread.new { Thread.current[:actions] = condition.run(cached_pid, now) }]
|
247
|
+
end
|
248
|
+
|
249
|
+
@transitioned = false
|
250
|
+
|
251
|
+
collect_conditions_actions(threads).each do |(action, reason)|
|
252
|
+
break if @transitioned
|
253
|
+
dispatch!(action, reason)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
def collect_conditions_actions(threads)
|
258
|
+
threads.inject([]) do |actions, (condition, thread)|
|
259
|
+
thread.join
|
260
|
+
thread[:actions].each do |action|
|
261
|
+
action_name = action.respond_to?(:call) ? "call to custom block" : action
|
262
|
+
Log[self].debug "Dispatching #{action_name} to #{name} for #{condition.to_s.strip}."
|
263
|
+
actions << [action, condition.to_s]
|
264
|
+
end
|
265
|
+
actions
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def notify_triggers(transition)
|
270
|
+
@triggers.each { |trigger| trigger.notify(transition) }
|
271
|
+
end
|
228
272
|
end
|
229
273
|
end
|
@@ -12,63 +12,52 @@ module Cognizant
|
|
12
12
|
|
13
13
|
private
|
14
14
|
|
15
|
-
def
|
16
|
-
before_command = options[:before]
|
17
|
-
command = options[:command]
|
18
|
-
after_command = options[:after]
|
19
|
-
signals = options[:signals]
|
20
|
-
timeout = options[:timeout] || 10
|
21
|
-
|
15
|
+
def handle_action(result_handler, options)
|
22
16
|
# TODO: Works well but can some refactoring make it more declarative?
|
23
17
|
@action_thread = Thread.new do
|
24
18
|
result = false
|
25
|
-
queue =
|
26
|
-
thread = Thread.new do
|
27
|
-
if before_command and not success = run(before_command).succeeded?
|
28
|
-
queue.push(success)
|
29
|
-
Thread.exit
|
30
|
-
end
|
19
|
+
queue, thread = execute_action(options)
|
31
20
|
|
32
|
-
|
33
|
-
|
34
|
-
queue.push(success)
|
35
|
-
Thread.exit
|
36
|
-
end
|
37
|
-
|
38
|
-
# If the caller has attempted to set signals, then it can handle it's result.
|
39
|
-
if success = send_signals(signals: signals, timeout: timeout)
|
40
|
-
run(after_command) if after_command
|
41
|
-
queue.push(success)
|
42
|
-
Thread.exit
|
43
|
-
end
|
44
|
-
|
45
|
-
queue.push(false)
|
46
|
-
Thread.exit
|
47
|
-
end
|
48
|
-
|
49
|
-
timeout_left = timeout + 1
|
50
|
-
while (timeout_left -= 1) > 0 do
|
21
|
+
time_left = options[:timeout]
|
22
|
+
while time_left >= 0 do
|
51
23
|
# If there is something in the queue, we have the required result.
|
52
|
-
|
53
|
-
|
54
|
-
skip_ticks_for(-timeout_left)
|
24
|
+
unless queue.empty?
|
25
|
+
result = queue.pop
|
55
26
|
break
|
56
27
|
end
|
57
28
|
sleep 1
|
29
|
+
time_left -= 1
|
58
30
|
end
|
59
31
|
|
60
32
|
# Kill the nested thread.
|
61
33
|
thread.kill
|
62
34
|
|
63
35
|
# Action callback.
|
64
|
-
|
65
|
-
|
66
|
-
# Kill self.
|
67
|
-
Thread.kill
|
36
|
+
self.send(result_handler, result, time_left) if result_handler.present? and self.respond_to?(result_handler)
|
68
37
|
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def execute_action(options)
|
41
|
+
before_command = options[:before]
|
42
|
+
command = options[:command]
|
43
|
+
after_command = options[:after]
|
44
|
+
signals = options[:signals]
|
45
|
+
timeout = options[:timeout]
|
69
46
|
|
70
|
-
|
71
|
-
|
47
|
+
queue = Queue.new
|
48
|
+
thread = Thread.new do
|
49
|
+
# If before_command succeeds, we move to the next command.
|
50
|
+
(before_command and not success = run(before_command).succeeded?) or
|
51
|
+
# If the command is available and it succeeds, we stop here.
|
52
|
+
(command and success = run(command, options) and success.succeeded?) or
|
53
|
+
# As a last try, check for signals. If the action has set signals, then it can handle its result.
|
54
|
+
(success = send_signals(signals: signals, timeout: timeout))
|
55
|
+
|
56
|
+
run(after_command) if success and after_command
|
57
|
+
queue.push(success)
|
58
|
+
Thread.exit
|
59
|
+
end
|
60
|
+
return queue, thread
|
72
61
|
end
|
73
62
|
|
74
63
|
def send_signals(options = {})
|
@@ -14,45 +14,101 @@ module Cognizant
|
|
14
14
|
# The command to restart the process with. This command can optionally
|
15
15
|
# be similar in behavior to the stop command, since the process will
|
16
16
|
# anyways be automatically started again, if autostart is set to true.
|
17
|
+
# Also see restart_expect variable.
|
17
18
|
# @return [String] Defaults to nil
|
18
19
|
attr_accessor :restart_command
|
19
20
|
|
20
21
|
# The signals to pass to the process one by one attempting to restart
|
21
22
|
# it. Each signal is passed within the timeout period over equally
|
22
|
-
#
|
23
|
+
# divided intervals (min. 2 seconds). Override with signals without
|
23
24
|
# "KILL" to never force kill the process.
|
25
|
+
# Also see restart_expect variable.
|
24
26
|
# e.g. ["TERM", "INT"]
|
25
|
-
# @return [Array] Defaults to ["
|
27
|
+
# @return [Array] Defaults to ["QUIT", "TERM", "INT"]
|
26
28
|
attr_accessor :restart_signals
|
27
29
|
|
30
|
+
# Whether or not the process is expected to stop itself after the
|
31
|
+
# restart action is executed. If, upon restart action, the process will
|
32
|
+
# stop but not start again by itself, it should be set to true. If the
|
33
|
+
# process will start again within the timeout period, it should be set
|
34
|
+
# to false. For convenience, it defaults to false, if restart_command
|
35
|
+
# or restart_signals are set, as the restart action is then expected to
|
36
|
+
# start itself after a stop.
|
37
|
+
# @return [true, false] Defaults to !restart_command.present? ||
|
38
|
+
# !restart_signals.present?
|
39
|
+
attr_accessor :restart_expect_stopped
|
40
|
+
|
28
41
|
# The grace time period in seconds for the process to stop within
|
29
42
|
# (for restart). Covers the time period for the restart command or
|
30
43
|
# signals. After the timeout is over, the process is checked for
|
31
44
|
# running status and if not stopped, it re-enters the auto start
|
32
|
-
# lifecycle based on conditions.
|
33
|
-
#
|
45
|
+
# lifecycle based on conditions. Timeout of request has the same effect
|
46
|
+
# as :stopped setting :restart_expect.
|
47
|
+
# @return [String] Defaults to 30
|
34
48
|
attr_accessor :restart_timeout
|
35
49
|
|
36
50
|
# The command to run after the process is restarted.
|
37
51
|
# @return [String] Defaults to nil
|
38
52
|
attr_accessor :restart_after_command
|
39
53
|
|
54
|
+
def restart_expect_stopped!
|
55
|
+
self.restart_expect_stopped = true
|
56
|
+
end
|
57
|
+
|
58
|
+
def restart_expect_stopped
|
59
|
+
unless !!@restart_expect_stopped == @restart_expect_stopped
|
60
|
+
@restart_expect_stopped = !(self.restart_command.present? or self.restart_signals.present?)
|
61
|
+
end
|
62
|
+
@restart_expect_stopped
|
63
|
+
end
|
64
|
+
|
65
|
+
def reset_attributes!
|
66
|
+
self.restart_env = {}
|
67
|
+
self.restart_before_command = nil
|
68
|
+
self.restart_command = nil
|
69
|
+
self.restart_signals = nil
|
70
|
+
self.restart_expect_stopped = nil
|
71
|
+
self.restart_timeout = 30
|
72
|
+
self.restart_after_command = nil
|
73
|
+
super
|
74
|
+
end
|
75
|
+
|
40
76
|
def restart_process
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
77
|
+
# We skip so that we're not reinformed about the required transition by the tick.
|
78
|
+
skip_ticks_for(self.restart_timeout)
|
79
|
+
|
80
|
+
options = {
|
81
|
+
env: self.env.merge(self.restart_env),
|
82
|
+
before: self.restart_before_command,
|
83
|
+
command: self.restart_command,
|
84
|
+
signals: self.restart_signals || ["QUIT", "TERM", "INT"],
|
85
|
+
after: self.restart_after_command,
|
86
|
+
timeout: self.restart_timeout
|
87
|
+
}
|
88
|
+
handle_action('_restart_result_handler', options)
|
89
|
+
end
|
90
|
+
|
91
|
+
# @private
|
92
|
+
def _restart_result_handler(result, time_left = 0)
|
93
|
+
# If it is a boolean and value is true OR if it's an execution result and it succeeded.
|
94
|
+
if (!!result == result and result) or (result.respond_to?(:succeeded?) and result.succeeded?)
|
95
|
+
unlink_pid if not pid_running? and self.daemonize
|
96
|
+
|
97
|
+
# We are not resetting @process_pid here to give process a second of grace period.
|
98
|
+
|
99
|
+
unless self.restart_expect_stopped
|
100
|
+
while (time_left >= 0 and not process_running?) do
|
101
|
+
sleep 1
|
102
|
+
time_left -= 1
|
103
|
+
@process_pid = nil
|
104
|
+
end
|
45
105
|
end
|
106
|
+
else
|
107
|
+
@process_pid = nil
|
46
108
|
end
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
before: self.restart_before_command,
|
51
|
-
command: self.restart_command,
|
52
|
-
signals: self.restart_signals,
|
53
|
-
after: self.restart_after_command,
|
54
|
-
timeout: self.restart_timeout
|
55
|
-
)
|
109
|
+
|
110
|
+
# Rollback the pending skips.
|
111
|
+
skip_ticks_for(-time_left) if time_left > 0
|
56
112
|
end
|
57
113
|
end
|
58
114
|
end
|