right_agent 2.1.5 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/right_agent/agent_tag_manager.rb +17 -9
- data/lib/right_agent/clients/api_client.rb +28 -27
- data/lib/right_agent/clients/balanced_http_client.rb +25 -5
- data/lib/right_agent/clients/base_retry_client.rb +76 -42
- data/lib/right_agent/clients/blocking_client.rb +11 -1
- data/lib/right_agent/clients/non_blocking_client.rb +32 -9
- data/lib/right_agent/clients/right_http_client.rb +14 -8
- data/lib/right_agent/clients/router_client.rb +41 -14
- data/lib/right_agent/command/command_client.rb +1 -0
- data/lib/right_agent/http_exceptions.rb +6 -1
- data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/process_patch.rb +2 -2
- data/lib/right_agent/offline_handler.rb +22 -9
- data/lib/right_agent/retryable_request.rb +18 -12
- data/lib/right_agent/scripts/agent_controller.rb +9 -3
- data/lib/right_agent/sender.rb +94 -61
- data/right_agent.gemspec +2 -2
- data/spec/agent_tag_manager_spec.rb +59 -14
- data/spec/clients/api_client_spec.rb +48 -36
- data/spec/clients/balanced_http_client_spec.rb +46 -2
- data/spec/clients/base_retry_client_spec.rb +118 -48
- data/spec/clients/blocking_client_spec.rb +16 -0
- data/spec/clients/non_blocking_client_spec.rb +43 -6
- data/spec/clients/router_client_spec.rb +54 -49
- data/spec/http_exceptions_spec.rb +7 -0
- data/spec/offline_handler_spec.rb +22 -11
- data/spec/retryable_request_spec.rb +35 -20
- data/spec/sender_spec.rb +185 -122
- metadata +3 -3
@@ -112,7 +112,7 @@ module RightScale
|
|
112
112
|
result
|
113
113
|
end
|
114
114
|
|
115
|
-
# Make long-polling requests until receive data or timeout
|
115
|
+
# Make long-polling requests until receive data, hit error, or timeout
|
116
116
|
#
|
117
117
|
# @param [Hash] connection to server from previous request with keys :host, :path,
|
118
118
|
# and :expires_at, with the :expires_at being adjusted on return
|
@@ -131,6 +131,16 @@ module RightScale
|
|
131
131
|
[result, code, body, headers]
|
132
132
|
end
|
133
133
|
|
134
|
+
# Close all persistent connections
|
135
|
+
#
|
136
|
+
# @param [String] reason for closing
|
137
|
+
#
|
138
|
+
# @return [TrueClass] always true
|
139
|
+
def close(reason)
|
140
|
+
@connections = {}
|
141
|
+
true
|
142
|
+
end
|
143
|
+
|
134
144
|
protected
|
135
145
|
|
136
146
|
# Make HTTP request once
|
@@ -123,17 +123,15 @@ module RightScale
|
|
123
123
|
# Make request an then yield fiber until it completes
|
124
124
|
fiber = Fiber.current
|
125
125
|
connection = EM::HttpRequest.new(uri.to_s, connect_options)
|
126
|
+
# Store connection now so that close will get called if terminating or reconnecting
|
127
|
+
c = @connections[path] = {:host => host, :connection => connection, :expires_at => Time.now} if request_options[:keepalive]
|
126
128
|
http = connection.send(verb, request_options)
|
127
|
-
http.errback { fiber.resume(http.error
|
128
|
-
(http.error && http.error.to_s) || "HTTP connection failure for #{verb.to_s.upcase}") }
|
129
|
+
http.errback { @connections.delete(path); fiber.resume(*handle_error(verb, http.error)) }
|
129
130
|
http.callback { fiber.resume(http.response_header.status, http.response, http.response_header) }
|
130
131
|
response_code, response_body, response_headers = Fiber.yield
|
131
132
|
response_headers = beautify_headers(response_headers) if response_headers
|
132
133
|
result = BalancedHttpClient.response(response_code, response_body, response_headers, request_options[:head][:accept])
|
133
|
-
if request_options[:keepalive]
|
134
|
-
expires_at = Time.now + BalancedHttpClient::CONNECTION_REUSE_TIMEOUT
|
135
|
-
@connections[path] = {:host => host, :connection => connection, :expires_at => expires_at}
|
136
|
-
end
|
134
|
+
c[:expires_at] = Time.now + BalancedHttpClient::CONNECTION_REUSE_TIMEOUT if request_options[:keepalive]
|
137
135
|
[result, response_code, response_body, response_headers]
|
138
136
|
end
|
139
137
|
|
@@ -159,9 +157,21 @@ module RightScale
|
|
159
157
|
[result, code, body, headers]
|
160
158
|
end
|
161
159
|
|
160
|
+
# Close all persistent connections
|
161
|
+
#
|
162
|
+
# @param [String] reason for closing
|
163
|
+
#
|
164
|
+
# @return [TrueClass] always true
|
165
|
+
def close(reason)
|
166
|
+
@connections.each_value { |c| c[:connection].close(reason) }
|
167
|
+
@connections = {}
|
168
|
+
true
|
169
|
+
end
|
170
|
+
|
162
171
|
protected
|
163
172
|
|
164
|
-
# Repeatedly make long-polling request until receive data or timeout
|
173
|
+
# Repeatedly make long-polling request until receive data, hit error, or timeout
|
174
|
+
# Treat "terminating" and "reconnecting" errors as an empty poll result
|
165
175
|
#
|
166
176
|
# @param [Symbol] verb for HTTP REST request
|
167
177
|
# @param [EM:HttpRequest] connection to server from previous request
|
@@ -173,8 +183,7 @@ module RightScale
|
|
173
183
|
# @raise [HttpException] HTTP failure with associated status code
|
174
184
|
def poll_again(fiber, connection, request_options, stop_at)
|
175
185
|
http = connection.send(:get, request_options)
|
176
|
-
http.errback { fiber.resume(http.error
|
177
|
-
(http.error && http.error.to_s) || "HTTP connection failure for POLL") }
|
186
|
+
http.errback { fiber.resume(*handle_error("POLL", http.error)) }
|
178
187
|
http.callback do
|
179
188
|
code, body, headers = http.response_header.status, http.response, http.response_header
|
180
189
|
if code == 200 && (body.nil? || body == "null") && Time.now < stop_at
|
@@ -186,6 +195,20 @@ module RightScale
|
|
186
195
|
true
|
187
196
|
end
|
188
197
|
|
198
|
+
# Handle error from request
|
199
|
+
#
|
200
|
+
# @param [Symbol] verb for HTTP REST request
|
201
|
+
# @param [Object] error result from HTTP connection
|
202
|
+
#
|
203
|
+
# @return [Array] status code and error message string
|
204
|
+
def handle_error(verb, error)
|
205
|
+
case error.to_s
|
206
|
+
when "terminating", "reconnecting" then [200, nil]
|
207
|
+
when "Errno::ETIMEDOUT" then [408, "Request timeout"]
|
208
|
+
else [500, (error && error.to_s) || "HTTP connection failure for #{verb.to_s.upcase}"]
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
189
212
|
# Beautify response header keys so that in same form as RestClient
|
190
213
|
#
|
191
214
|
# @param [Hash] headers from response
|
@@ -93,8 +93,11 @@ module RightScale
|
|
93
93
|
# Packet::GLOBAL, ones with no shard id
|
94
94
|
# [Symbol] :selector for picking from qualified targets: :any or :all;
|
95
95
|
# defaults to :any
|
96
|
-
#
|
97
|
-
#
|
96
|
+
#
|
97
|
+
# @option options [String] :request_uuid uniquely identifying this request; defaults to
|
98
|
+
# randomly generated
|
99
|
+
# @option options [Numeric] :time_to_live seconds before request expires and is to be ignored;
|
100
|
+
# non-positive value or nil means never expire
|
98
101
|
#
|
99
102
|
# @return [NilClass] always nil since there is no expected response to the request
|
100
103
|
#
|
@@ -105,10 +108,10 @@ module RightScale
|
|
105
108
|
# @raise [Exceptions::RetryableError] request failed but if retried may succeed
|
106
109
|
# @raise [Exceptions::Terminating] closing client and terminating service
|
107
110
|
# @raise [Exceptions::InternalServerError] internal error in server being accessed
|
108
|
-
def push(type, payload = nil, target = nil,
|
111
|
+
def push(type, payload = nil, target = nil, options = {})
|
109
112
|
raise RuntimeError, "#{self.class.name}#init was not called" unless @auth
|
110
113
|
client = (@api && @api.support?(type)) ? @api : @router
|
111
|
-
client.push(type, payload, target,
|
114
|
+
client.push(type, payload, target, options)
|
112
115
|
end
|
113
116
|
|
114
117
|
# Route a request to a single target with a response expected
|
@@ -127,8 +130,11 @@ module RightScale
|
|
127
130
|
# [Array] :tags that must all be associated with a target for it to be selected
|
128
131
|
# [Hash] :scope for restricting routing which may contain:
|
129
132
|
# [Integer] :account id that agents must be associated with to be included
|
130
|
-
#
|
131
|
-
#
|
133
|
+
#
|
134
|
+
# @option options [String] :request_uuid uniquely identifying this request; defaults to
|
135
|
+
# randomly generated
|
136
|
+
# @option options [Numeric] :time_to_live seconds before request expires and is to be ignored;
|
137
|
+
# non-positive value or nil means never expire
|
132
138
|
#
|
133
139
|
# @return [Result, NilClass] response from request
|
134
140
|
#
|
@@ -139,10 +145,10 @@ module RightScale
|
|
139
145
|
# @raise [Exceptions::RetryableError] request failed but if retried may succeed
|
140
146
|
# @raise [Exceptions::Terminating] closing client and terminating service
|
141
147
|
# @raise [Exceptions::InternalServerError] internal error in server being accessed
|
142
|
-
def request(type, payload = nil, target = nil,
|
148
|
+
def request(type, payload = nil, target = nil, options = {})
|
143
149
|
raise RuntimeError, "#{self.class.name}#init was not called" unless @auth
|
144
150
|
client = (@api && @api.support?(type)) ? @api : @router
|
145
|
-
client.request(type, payload, target,
|
151
|
+
client.request(type, payload, target, options)
|
146
152
|
end
|
147
153
|
|
148
154
|
# Route event
|
@@ -54,7 +54,7 @@ module RightScale
|
|
54
54
|
RECONNECT_INTERVAL = 2
|
55
55
|
|
56
56
|
# Maximum interval between attempts to reconnect or long-poll when router is not responding
|
57
|
-
MAX_RECONNECT_INTERVAL =
|
57
|
+
MAX_RECONNECT_INTERVAL = 30
|
58
58
|
|
59
59
|
# Interval between checks for lost WebSocket connection
|
60
60
|
CHECK_INTERVAL = 5
|
@@ -116,8 +116,11 @@ module RightScale
|
|
116
116
|
# Packet::GLOBAL, ones with no shard id
|
117
117
|
# [Symbol] :selector for picking from qualified targets: :any or :all;
|
118
118
|
# defaults to :any
|
119
|
-
#
|
120
|
-
#
|
119
|
+
#
|
120
|
+
# @option options [String] :request_uuid uniquely identifying this request; defaults to
|
121
|
+
# randomly generated
|
122
|
+
# @option options [Numeric] :time_to_live seconds before request expires and is to be ignored;
|
123
|
+
# non-positive value or nil means never expire
|
121
124
|
#
|
122
125
|
# @return [NilClass] always nil since there is no expected response to the request
|
123
126
|
#
|
@@ -127,12 +130,12 @@ module RightScale
|
|
127
130
|
# @raise [Exceptions::RetryableError] request failed but if retried may succeed
|
128
131
|
# @raise [Exceptions::Terminating] closing client and terminating service
|
129
132
|
# @raise [Exceptions::InternalServerError] internal error in server being accessed
|
130
|
-
def push(type, payload, target,
|
133
|
+
def push(type, payload, target, options = {})
|
131
134
|
params = {
|
132
135
|
:type => type,
|
133
136
|
:payload => payload,
|
134
137
|
:target => target }
|
135
|
-
make_request(:post, "/push", params, type.split("/")[2],
|
138
|
+
make_request(:post, "/push", params, type.split("/")[2], options)
|
136
139
|
end
|
137
140
|
|
138
141
|
# Route a request to a single target with a response expected
|
@@ -152,8 +155,11 @@ module RightScale
|
|
152
155
|
# [Array] :tags that must all be associated with a target for it to be selected
|
153
156
|
# [Hash] :scope for restricting routing which may contain:
|
154
157
|
# [Integer] :account id that agents must be associated with to be included
|
155
|
-
#
|
156
|
-
#
|
158
|
+
#
|
159
|
+
# @option options [String] :request_uuid uniquely identifying this request; defaults to
|
160
|
+
# randomly generated
|
161
|
+
# @option options [Numeric] :time_to_live seconds before request expires and is to be ignored;
|
162
|
+
# non-positive value or nil means never expire
|
157
163
|
#
|
158
164
|
# @return [Result, NilClass] response from request
|
159
165
|
#
|
@@ -163,12 +169,12 @@ module RightScale
|
|
163
169
|
# @raise [Exceptions::RetryableError] request failed but if retried may succeed
|
164
170
|
# @raise [Exceptions::Terminating] closing client and terminating service
|
165
171
|
# @raise [Exceptions::InternalServerError] internal error in server being accessed
|
166
|
-
def request(type, payload, target,
|
172
|
+
def request(type, payload, target, options = {})
|
167
173
|
params = {
|
168
174
|
:type => type,
|
169
175
|
:payload => payload,
|
170
176
|
:target => target }
|
171
|
-
make_request(:post, "/request", params, type.split("/")[2],
|
177
|
+
make_request(:post, "/request", params, type.split("/")[2], options)
|
172
178
|
end
|
173
179
|
|
174
180
|
# Route event
|
@@ -198,7 +204,7 @@ module RightScale
|
|
198
204
|
Log.info("Sending EVENT <#{event[:uuid]}> #{event[:type]}#{path}#{to}")
|
199
205
|
@websocket.send(JSON.dump(params))
|
200
206
|
else
|
201
|
-
make_request(:post, "/notify", params, "notify", event[:uuid], :filter_params => ["event"])
|
207
|
+
make_request(:post, "/notify", params, "notify", :request_uuid => event[:uuid], :filter_params => ["event"])
|
202
208
|
end
|
203
209
|
true
|
204
210
|
end
|
@@ -344,11 +350,32 @@ module RightScale
|
|
344
350
|
@listen_interval = CHECK_INTERVAL
|
345
351
|
end
|
346
352
|
|
347
|
-
|
353
|
+
listen_loop_wait(Time.now, @listen_interval, routing_keys, &handler)
|
354
|
+
end
|
355
|
+
|
356
|
+
# Wait specified interval before next listen loop
|
357
|
+
# Continue waiting if interval changes while waiting
|
358
|
+
#
|
359
|
+
# @param [Time] started_at time when first started waiting
|
360
|
+
# @param [Numeric] interval to wait
|
361
|
+
# @param [Array, NilClass] routing_keys for event sources of interest with nil meaning all
|
362
|
+
#
|
363
|
+
# @yield [event] required block called each time event received
|
364
|
+
# @yieldparam [Hash] event received
|
365
|
+
#
|
366
|
+
# @return [TrueClass] always true
|
367
|
+
def listen_loop_wait(started_at, interval, routing_keys, &handler)
|
348
368
|
if @listen_interval == 0
|
349
369
|
EM_S.next_tick { listen_loop(routing_keys, &handler) }
|
350
370
|
else
|
351
|
-
@listen_timer = EM_S::Timer.new(
|
371
|
+
@listen_timer = EM_S::Timer.new(interval) do
|
372
|
+
remaining = @listen_interval - (Time.now - started_at)
|
373
|
+
if remaining > 0
|
374
|
+
listen_loop_wait(started_at, remaining, routing_keys, &handler)
|
375
|
+
else
|
376
|
+
listen_loop(routing_keys, &handler)
|
377
|
+
end
|
378
|
+
end
|
352
379
|
end
|
353
380
|
true
|
354
381
|
end
|
@@ -555,7 +582,7 @@ module RightScale
|
|
555
582
|
:poll_timeout => @options[:listen_timeout] }
|
556
583
|
|
557
584
|
event_uuids = []
|
558
|
-
events = make_request(:poll, "/listen", params, "listen",
|
585
|
+
events = make_request(:poll, "/listen", params, "listen", options)
|
559
586
|
if events
|
560
587
|
events.each do |event|
|
561
588
|
event = SerializationHelper.symbolize_keys(event)
|
@@ -610,7 +637,7 @@ module RightScale
|
|
610
637
|
#
|
611
638
|
# @return [Boolean] true if router not responding, otherwise false
|
612
639
|
def router_not_responding?
|
613
|
-
@close_code == PROTOCOL_ERROR_CLOSE && @close_reason =~ /502|503/
|
640
|
+
@close_code == PROTOCOL_ERROR_CLOSE && @close_reason =~ /408|502|503/
|
614
641
|
end
|
615
642
|
|
616
643
|
end # RouterClient
|
@@ -82,6 +82,7 @@ module RightScale
|
|
82
82
|
@pending += 1
|
83
83
|
command = options.dup
|
84
84
|
command[:verbose] = verbose
|
85
|
+
command[:timeout] = timeout
|
85
86
|
command[:cookie] = @cookie
|
86
87
|
EM.next_tick { EM.connect('127.0.0.1', @socket_port, ConnectionHandler, command, self, response_handler) }
|
87
88
|
EM.add_timer(timeout) { EM.stop; raise 'Timed out waiting for agent reply' } if manage_em
|
@@ -69,7 +69,12 @@ module RightScale
|
|
69
69
|
|
70
70
|
# Convert RestClient exception
|
71
71
|
def self.convert(e)
|
72
|
-
e2 =
|
72
|
+
e2 = if e.is_a?(RestClient::RequestTimeout)
|
73
|
+
# Special case RequestTimeout because http_code and http_body is typically nil given no actual response
|
74
|
+
create(408)
|
75
|
+
else
|
76
|
+
create(e.http_code, e.http_body, RightScale::Response.new((e.response && e.response.headers) || {}))
|
77
|
+
end
|
73
78
|
e2.message = e.message
|
74
79
|
e2
|
75
80
|
end
|
@@ -44,12 +44,12 @@ begin
|
|
44
44
|
@@win32_kill.call(sig, *pids)
|
45
45
|
end
|
46
46
|
|
47
|
-
# implements getpgid() for
|
47
|
+
# implements getpgid() for Windows
|
48
48
|
def self.getpgid(pid)
|
49
49
|
# FIX: we currently only use this to check if the process is running.
|
50
50
|
# it is possible to get the parent process id for a process in Windows if
|
51
51
|
# we actually need this info.
|
52
|
-
return Process.kill(0, pid).
|
52
|
+
return Process.kill(0, pid).include?(pid) ? 0 : -1
|
53
53
|
rescue
|
54
54
|
raise Errno::ESRCH
|
55
55
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (c) 2009-
|
2
|
+
# Copyright (c) 2009-2014 RightScale Inc
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining
|
5
5
|
# a copy of this software and associated documentation files (the
|
@@ -27,7 +27,7 @@ module RightScale
|
|
27
27
|
class OfflineHandler
|
28
28
|
|
29
29
|
# Maximum seconds to wait before starting flushing offline queue when disabling offline mode
|
30
|
-
MAX_QUEUE_FLUSH_DELAY =
|
30
|
+
MAX_QUEUE_FLUSH_DELAY = 60
|
31
31
|
|
32
32
|
# Maximum number of offline queued requests before triggering restart vote
|
33
33
|
MAX_QUEUED_REQUESTS = 100
|
@@ -161,12 +161,23 @@ module RightScale
|
|
161
161
|
# Queue given request in memory
|
162
162
|
#
|
163
163
|
# === Parameters
|
164
|
-
#
|
164
|
+
# kind(Symbol):: Kind of request: :send_push or :send_request
|
165
|
+
# type(String):: Dispatch route for the request; typically identifies actor and action
|
166
|
+
# payload(Object):: Data to be sent with marshalling en route
|
167
|
+
# target(Hash|NilClass):: Target for request
|
168
|
+
# token(String):: Token uniquely identifying request
|
169
|
+
# expires_at(Integer):: Time in seconds in Unix-epoch when this request expires and
|
170
|
+
# is to be ignored by the receiver; value 0 means never expire
|
171
|
+
#
|
172
|
+
# === Block
|
173
|
+
# Optional block used to process response asynchronously with the following parameter:
|
174
|
+
# result(Result):: Response with an OperationResult of SUCCESS, RETRY, NON_DELIVERY, or ERROR
|
165
175
|
#
|
166
176
|
# === Return
|
167
177
|
# true:: Always return true
|
168
|
-
def queue_request(kind, type, payload, target, callback)
|
169
|
-
request = {:kind => kind, :type => type, :payload => payload, :target => target,
|
178
|
+
def queue_request(kind, type, payload, target, token, expires_at, &callback)
|
179
|
+
request = {:kind => kind, :type => type, :payload => payload, :target => target,
|
180
|
+
:token => token, :expires_at => expires_at, :callback => callback}
|
170
181
|
Log.info("[offline] Queuing request: #{request.inspect}")
|
171
182
|
vote_to_restart if (@restart_vote_count += 1) >= MAX_QUEUED_REQUESTS
|
172
183
|
if @state == :initializing
|
@@ -190,7 +201,7 @@ module RightScale
|
|
190
201
|
|
191
202
|
protected
|
192
203
|
|
193
|
-
# Send any requests that were queued while in offline mode
|
204
|
+
# Send any requests that were queued while in offline mode and have not yet timed out
|
194
205
|
# Do this asynchronously to allow for agents to respond to requests
|
195
206
|
# Once all in-memory requests have been flushed, switch off offline mode
|
196
207
|
#
|
@@ -204,10 +215,12 @@ module RightScale
|
|
204
215
|
Log.info("[offline] Starting to flush request queue of size #{@queue.size}") unless again || @mode == :initializing
|
205
216
|
if @queue.any?
|
206
217
|
r = @queue.shift
|
207
|
-
|
208
|
-
|
218
|
+
options = {:token => r[:token]}
|
219
|
+
if r[:expires_at] != 0 && (options[:time_to_live] = r[:expires_at] - Time.now.to_i) <= 0
|
220
|
+
Log.info("[offline] Dropping queued request <#{r[:token]}> because it expired " +
|
221
|
+
"#{(-options[:time_to_live]).round} sec ago")
|
209
222
|
else
|
210
|
-
Sender.instance.send(r[:kind], r[:type], r[:payload], r[:target])
|
223
|
+
Sender.instance.send(r[:kind], r[:type], r[:payload], r[:target], options, &r[:callback])
|
211
224
|
end
|
212
225
|
end
|
213
226
|
if @queue.empty?
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (c) 2009-
|
2
|
+
# Copyright (c) 2009-2014 RightScale Inc
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining
|
5
5
|
# a copy of this software and associated documentation files (the
|
@@ -74,13 +74,13 @@ module RightScale
|
|
74
74
|
# options(Hash):: Request options
|
75
75
|
# :targets(Array):: Target agent identities from which to randomly choose one
|
76
76
|
# :retry_on_error(Boolean):: Whether request should be retried if recipient returned an error
|
77
|
-
# :retry_delay(
|
77
|
+
# :retry_delay(Numeric):: Number of seconds delay before initial retry with -1 meaning no delay,
|
78
78
|
# defaults to DEFAULT_RETRY_DELAY
|
79
|
-
# :retry_delay_count(
|
79
|
+
# :retry_delay_count(Numeric):: Minimum number of retries at initial :retry_delay value before
|
80
80
|
# increasing delay exponentially and decreasing this count exponentially, defaults to
|
81
81
|
# DEFAULT_RETRY_DELAY_COUNT
|
82
|
-
# :max_retry_delay(
|
83
|
-
# :timeout(
|
82
|
+
# :max_retry_delay(Numeric):: Maximum number of seconds of retry delay, defaults to DEFAULT_MAX_RETRY_DELAY
|
83
|
+
# :timeout(Numeric):: Number of seconds with no response before error callback gets called, with
|
84
84
|
# -1 meaning never, defaults to DEFAULT_TIMEOUT
|
85
85
|
#
|
86
86
|
# === Raises
|
@@ -90,6 +90,7 @@ module RightScale
|
|
90
90
|
raise ArgumentError.new("payload is required") unless (@payload = payload)
|
91
91
|
@retry_on_error = options[:retry_on_error]
|
92
92
|
@timeout = options[:timeout] || DEFAULT_TIMEOUT
|
93
|
+
@expires_at = Time.now.to_i + @timeout if @timeout > 0
|
93
94
|
@retry_delay = options[:retry_delay] || DEFAULT_RETRY_DELAY
|
94
95
|
@retry_delay_count = options[:retry_delay_count] || DEFAULT_RETRY_DELAY_COUNT
|
95
96
|
@max_retry_delay = options[:max_retry_delay] || DEFAULT_MAX_RETRY_DELAY
|
@@ -105,13 +106,18 @@ module RightScale
|
|
105
106
|
# === Return
|
106
107
|
# true:: Always return true
|
107
108
|
def run
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
109
|
+
cancel = Proc.new do
|
110
|
+
msg = "Request #{@operation} timed out after #{@timeout} seconds"
|
111
|
+
Log.info(msg)
|
112
|
+
cancel(msg)
|
113
|
+
end
|
114
|
+
|
115
|
+
options = {}
|
116
|
+
if @expires_at.nil? || (options[:time_to_live] = @expires_at - Time.now.to_i) > 0
|
117
|
+
Sender.instance.send_request(@operation, @payload, retrieve_target(@targets), options) { |r| handle_response(r) }
|
118
|
+
@cancel_timer = EM::Timer.new(@timeout) { cancel.call } if @cancel_timer.nil? && @timeout > 0
|
119
|
+
else
|
120
|
+
cancel.call
|
115
121
|
end
|
116
122
|
true
|
117
123
|
end
|
@@ -404,9 +404,15 @@ module RightScale
|
|
404
404
|
pgid = Process.getpgid(pid) rescue -1
|
405
405
|
name = human_readable_name(agent_name, pid_file.identity)
|
406
406
|
if pgid != -1
|
407
|
-
|
408
|
-
|
409
|
-
|
407
|
+
message = "#{name} is alive"
|
408
|
+
unless RightScale::Platform.windows?
|
409
|
+
# Windows Platform code currently does not support retrieving memory usage
|
410
|
+
# information for another process, so only include it for linux
|
411
|
+
psdata = `ps up #{pid}`.split("\n").last.split
|
412
|
+
memory = (psdata[5].to_i / 1024)
|
413
|
+
message << ", using #{memory}MB of memory"
|
414
|
+
end
|
415
|
+
puts message
|
410
416
|
res = true
|
411
417
|
else
|
412
418
|
puts "#{name} is not running but has a stale pid file at #{pid_file}"
|