right_agent 0.13.5 → 0.14.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.
- data/lib/right_agent/actors/agent_manager.rb +1 -32
- data/lib/right_agent/agent.rb +243 -230
- data/lib/right_agent/dispatched_cache.rb +4 -5
- data/lib/right_agent/dispatcher.rb +146 -157
- data/lib/right_agent/pid_file.rb +1 -1
- data/lib/right_agent/platform.rb +14 -14
- data/lib/right_agent/scripts/agent_controller.rb +2 -4
- data/lib/right_agent/sender.rb +214 -223
- data/lib/right_agent/serialize/secure_serializer.rb +2 -2
- data/right_agent.gemspec +3 -3
- data/spec/agent_spec.rb +50 -171
- data/spec/dispatched_cache_spec.rb +13 -19
- data/spec/dispatcher_spec.rb +192 -254
- data/spec/sender_spec.rb +212 -168
- metadata +7 -4
@@ -24,7 +24,7 @@ module RightScale
|
|
24
24
|
|
25
25
|
# Cache for requests that have been dispatched recently
|
26
26
|
# This cache is intended for use in checking for duplicate requests
|
27
|
-
#
|
27
|
+
# when there is only one server servicing a queue
|
28
28
|
class DispatchedCache
|
29
29
|
|
30
30
|
# Maximum number of seconds to retain a dispatched request in cache
|
@@ -43,16 +43,15 @@ module RightScale
|
|
43
43
|
@max_age = MAX_AGE
|
44
44
|
end
|
45
45
|
|
46
|
-
# Store dispatched request token in cache
|
46
|
+
# Store dispatched request token in cache
|
47
47
|
#
|
48
48
|
# === Parameters
|
49
49
|
# token(String):: Generated message identifier
|
50
|
-
# shared_queue(String|nil):: Name of shared queue if being dispatched from a shared queue
|
51
50
|
#
|
52
51
|
# === Return
|
53
52
|
# true:: Always return true
|
54
|
-
def store(token
|
55
|
-
if token
|
53
|
+
def store(token)
|
54
|
+
if token
|
56
55
|
now = Time.now.to_i
|
57
56
|
if @cache.has_key?(token)
|
58
57
|
@cache[token] = now
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (c) 2009-
|
2
|
+
# Copyright (c) 2009-2012 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
|
@@ -25,8 +25,8 @@ module RightScale
|
|
25
25
|
# Dispatching of payload to specified actor
|
26
26
|
class Dispatcher
|
27
27
|
|
28
|
-
|
29
|
-
|
28
|
+
class InvalidRequestType < Exception; end
|
29
|
+
class DuplicateRequest < Exception; end
|
30
30
|
|
31
31
|
# (ActorRegistry) Registry for actors
|
32
32
|
attr_reader :registry
|
@@ -34,164 +34,67 @@ module RightScale
|
|
34
34
|
# (String) Identity of associated agent
|
35
35
|
attr_reader :identity
|
36
36
|
|
37
|
-
#
|
38
|
-
|
39
|
-
|
40
|
-
# (
|
41
|
-
|
37
|
+
# For direct access to current dispatcher
|
38
|
+
#
|
39
|
+
# === Return
|
40
|
+
# (Dispatcher):: This dispatcher instance if defined, otherwise nil
|
41
|
+
def self.instance
|
42
|
+
@@instance if defined?(@@instance)
|
43
|
+
end
|
42
44
|
|
43
45
|
# Initialize dispatcher
|
44
46
|
#
|
45
47
|
# === Parameters
|
46
|
-
# agent(Agent):: Agent using this dispatcher; uses its identity
|
47
|
-
# :secure(Boolean):: true indicates to use Security features of RabbitMQ to restrict agents to themselves
|
48
|
-
# :single_threaded(Boolean):: true indicates to run all operations in one thread; false indicates
|
49
|
-
# to do requested work on event machine defer thread and all else, such as pings on main thread
|
50
|
-
# :threadpool_size(Integer):: Number of threads in event machine thread pool
|
48
|
+
# agent(Agent):: Agent using this dispatcher; uses its identity and registry
|
51
49
|
# dispatched_cache(DispatchedCache|nil):: Cache for dispatched requests that is used for detecting
|
52
50
|
# duplicate requests, or nil if duplicate checking is disabled
|
53
51
|
def initialize(agent, dispatched_cache = nil)
|
54
52
|
@agent = agent
|
55
|
-
@broker = @agent.broker
|
56
53
|
@registry = @agent.registry
|
57
54
|
@identity = @agent.identity
|
58
|
-
|
59
|
-
@secure = options[:secure]
|
60
|
-
@single_threaded = options[:single_threaded]
|
61
|
-
@pending_dispatches = 0
|
62
|
-
@em = EM
|
63
|
-
@em.threadpool_size = (options[:threadpool_size] || 20).to_i
|
55
|
+
@dispatched_cache = dispatched_cache
|
64
56
|
reset_stats
|
57
|
+
@@instance = self
|
58
|
+
end
|
65
59
|
|
66
|
-
|
67
|
-
|
60
|
+
# Determine whether able to route requests to specified actor
|
61
|
+
#
|
62
|
+
# === Parameters
|
63
|
+
# actor(String):: Actor name
|
64
|
+
#
|
65
|
+
# === Return
|
66
|
+
# (Boolean):: true if can route to actor, otherwise false
|
67
|
+
def routable?(actor)
|
68
|
+
!!@registry.actor_for(actor)
|
68
69
|
end
|
69
70
|
|
70
|
-
#
|
71
|
-
# Handle returning of result to requester including logging any exceptions
|
71
|
+
# Route request to appropriate actor for servicing
|
72
72
|
# Reject requests whose TTL has expired or that are duplicates of work already dispatched
|
73
|
-
# Work is done in background defer thread if single threaded option is false
|
74
|
-
# Acknowledge request after actor has responded
|
75
73
|
#
|
76
74
|
# === Parameters
|
77
75
|
# request(Request|Push):: Packet containing request
|
78
76
|
# header(AMQP::Frame::Header|nil):: Request header containing ack control
|
79
|
-
# shared_queue(String|nil):: Name of shared queue if being dispatched from a shared queue
|
80
77
|
#
|
81
78
|
# === Return
|
82
|
-
# (Result|nil):: Result
|
83
|
-
def dispatch(request, header = nil, shared_queue = nil)
|
84
|
-
begin
|
85
|
-
ack_deferred = false
|
86
|
-
|
87
|
-
# Determine which actor this request is for
|
88
|
-
prefix, method = request.type.split('/')[1..-1]
|
89
|
-
method ||= :index
|
90
|
-
method = method.to_sym
|
91
|
-
actor = @registry.actor_for(prefix)
|
92
|
-
token = request.token
|
93
|
-
received_at = @requests.update(method, (token if request.kind_of?(Request)))
|
94
|
-
if actor.nil?
|
95
|
-
Log.error("No actor for dispatching request <#{token}> of type #{request.type}")
|
96
|
-
return nil
|
97
|
-
end
|
98
|
-
method_idempotent = actor.class.idempotent?(method)
|
99
|
-
|
100
|
-
# Reject this request if its TTL has expired
|
101
|
-
if (expires_at = request.expires_at) && expires_at > 0 && received_at.to_i >= expires_at
|
102
|
-
@rejects.update("expired (#{method})")
|
103
|
-
Log.info("REJECT EXPIRED <#{token}> from #{request.from} TTL #{RightSupport::Stats.elapsed(received_at.to_i - expires_at)} ago")
|
104
|
-
if request.is_a?(Request)
|
105
|
-
# For agents that do not know about non-delivery, use error result
|
106
|
-
non_delivery = if request.recv_version < 13
|
107
|
-
OperationResult.error("Could not deliver request (#{OperationResult::TTL_EXPIRATION})")
|
108
|
-
else
|
109
|
-
OperationResult.non_delivery(OperationResult::TTL_EXPIRATION)
|
110
|
-
end
|
111
|
-
result = Result.new(token, request.reply_to, non_delivery, @identity, request.from, request.tries, request.persistent)
|
112
|
-
exchange = {:type => :queue, :name => RESPONSE_QUEUE, :options => {:durable => true, :no_declare => @secure}}
|
113
|
-
@broker.publish(exchange, result, :persistent => true, :mandatory => true)
|
114
|
-
end
|
115
|
-
return nil
|
116
|
-
end
|
117
|
-
|
118
|
-
# Reject this request if it is a duplicate
|
119
|
-
if !method_idempotent && @dispatched_cache
|
120
|
-
if by = @dispatched_cache.serviced_by(token)
|
121
|
-
@rejects.update("duplicate (#{method})")
|
122
|
-
Log.info("REJECT DUP <#{token}> serviced by #{by == @identity ? 'self' : by}")
|
123
|
-
return nil
|
124
|
-
end
|
125
|
-
request.tries.each do |t|
|
126
|
-
if by = @dispatched_cache.serviced_by(t)
|
127
|
-
@rejects.update("retry duplicate (#{method})")
|
128
|
-
Log.info("REJECT RETRY DUP <#{token}> of <#{t}> serviced by #{by == @identity ? 'self' : by}")
|
129
|
-
return nil
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
# Proc for performing request in actor
|
135
|
-
operation = lambda do
|
136
|
-
begin
|
137
|
-
@pending_dispatches += 1
|
138
|
-
@last_request_dispatch_time = received_at.to_i
|
139
|
-
@dispatched_cache.store(token, shared_queue) if !method_idempotent && @dispatched_cache
|
140
|
-
if actor.method(method).arity.abs == 1
|
141
|
-
actor.__send__(method, request.payload)
|
142
|
-
else
|
143
|
-
actor.__send__(method, request.payload, request)
|
144
|
-
end
|
145
|
-
rescue Exception => e
|
146
|
-
@pending_dispatches = [@pending_dispatches - 1, 0].max
|
147
|
-
OperationResult.error(handle_exception(actor, method, request, e))
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
# Proc for sending response
|
152
|
-
callback = lambda do |r|
|
153
|
-
begin
|
154
|
-
if request.kind_of?(Request)
|
155
|
-
duration = @requests.finish(received_at, token)
|
156
|
-
r = Result.new(token, request.reply_to, r, @identity, request.from, request.tries, request.persistent, duration)
|
157
|
-
exchange = {:type => :queue, :name => RESPONSE_QUEUE, :options => {:durable => true, :no_declare => @secure}}
|
158
|
-
@broker.publish(exchange, r, :persistent => true, :mandatory => true, :log_filter => [:tries, :persistent, :duration])
|
159
|
-
end
|
160
|
-
rescue RightAMQP::HABrokerClient::NoConnectedBrokers => e
|
161
|
-
Log.error("Failed to publish result of dispatched request #{request.trace}", e)
|
162
|
-
rescue Exception => e
|
163
|
-
Log.error("Failed to publish result of dispatched request #{request.trace}", e, :trace)
|
164
|
-
@exceptions.track("publish response", e)
|
165
|
-
ensure
|
166
|
-
header.ack if header
|
167
|
-
@pending_dispatches = [@pending_dispatches - 1, 0].max
|
168
|
-
end
|
169
|
-
r # For unit tests
|
170
|
-
end
|
171
|
-
|
172
|
-
# Process request and send response, if any
|
173
|
-
begin
|
174
|
-
ack_deferred = true
|
175
|
-
if @single_threaded
|
176
|
-
@em.next_tick { callback.call(operation.call) }
|
177
|
-
else
|
178
|
-
@em.defer(operation, callback)
|
179
|
-
end
|
180
|
-
rescue Exception
|
181
|
-
header.ack if header
|
182
|
-
raise
|
183
|
-
end
|
184
|
-
ensure
|
185
|
-
header.ack unless ack_deferred || header.nil?
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
# Determine age of youngest request dispatch
|
79
|
+
# (Result|nil):: Result of request, or nil if there is no result because request is a Push
|
190
80
|
#
|
191
|
-
# ===
|
192
|
-
#
|
193
|
-
|
194
|
-
|
81
|
+
# === Raise
|
82
|
+
# InvalidRequestType:: If the request cannot be routed to an actor
|
83
|
+
# DuplicateRequest:: If request rejected because it has already been processed
|
84
|
+
def dispatch(request)
|
85
|
+
token = request.token
|
86
|
+
actor, method, idempotent = route(request)
|
87
|
+
received_at = @request_stats.update(method, (token if request.is_a?(Request)))
|
88
|
+
if dup = duplicate?(request, method, idempotent)
|
89
|
+
raise DuplicateRequest.new(dup)
|
90
|
+
end
|
91
|
+
unless result = expired?(request, method)
|
92
|
+
result = perform(request, actor, method, idempotent)
|
93
|
+
end
|
94
|
+
if request.is_a?(Request)
|
95
|
+
duration = @request_stats.finish(received_at, token)
|
96
|
+
Result.new(token, request.reply_to, result, @identity, request.from, request.tries, request.persistent, duration)
|
97
|
+
end
|
195
98
|
end
|
196
99
|
|
197
100
|
# Get dispatcher statistics
|
@@ -203,30 +106,25 @@ module RightScale
|
|
203
106
|
# stats(Hash):: Current statistics:
|
204
107
|
# "dispatched cache"(Hash|nil):: Number of dispatched requests cached and age of youngest and oldest,
|
205
108
|
# or nil if empty
|
109
|
+
# "dispatch failures"(Hash|nil):: Dispatch failure activity stats with keys "total", "percent", "last", and "rate"
|
110
|
+
# with percentage breakdown per failure type, or nil if none
|
206
111
|
# "exceptions"(Hash|nil):: Exceptions raised per category, or nil if none
|
207
112
|
# "total"(Integer):: Total for category
|
208
113
|
# "recent"(Array):: Most recent as a hash of "count", "type", "message", "when", and "where"
|
209
114
|
# "rejects"(Hash|nil):: Request reject activity stats with keys "total", "percent", "last", and "rate"
|
210
|
-
# "pending"(Hash|nil):: Pending request "total" and "youngest age", or nil if none
|
211
115
|
# with percentage breakdown per reason ("duplicate (<method>)", "retry duplicate (<method>)", or
|
212
116
|
# "stale (<method>)"), or nil if none
|
213
117
|
# "requests"(Hash|nil):: Request activity stats with keys "total", "percent", "last", and "rate"
|
214
118
|
# with percentage breakdown per request type, or nil if none
|
215
119
|
# "response time"(Float):: Average number of seconds to respond to a request recently
|
216
120
|
def stats(reset = false)
|
217
|
-
pending = if @pending_dispatches > 0
|
218
|
-
{
|
219
|
-
"total" => @pending_dispatches,
|
220
|
-
"youngest age" => dispatch_age
|
221
|
-
}
|
222
|
-
end
|
223
121
|
stats = {
|
224
|
-
"dispatched cache"
|
225
|
-
"
|
226
|
-
"
|
227
|
-
"rejects"
|
228
|
-
"requests"
|
229
|
-
"response time"
|
122
|
+
"dispatched cache" => (@dispatched_cache.stats if @dispatched_cache),
|
123
|
+
"dispatch failures" => @dispatch_failure_stats.all,
|
124
|
+
"exceptions" => @exception_stats.stats,
|
125
|
+
"rejects" => @reject_stats.all,
|
126
|
+
"requests" => @request_stats.all,
|
127
|
+
"response time" => @request_stats.avg_duration
|
230
128
|
}
|
231
129
|
reset_stats if reset
|
232
130
|
stats
|
@@ -239,12 +137,103 @@ module RightScale
|
|
239
137
|
# === Return
|
240
138
|
# true:: Always return true
|
241
139
|
def reset_stats
|
242
|
-
@
|
243
|
-
@
|
244
|
-
@
|
140
|
+
@reject_stats = RightSupport::Stats::Activity.new
|
141
|
+
@request_stats = RightSupport::Stats::Activity.new
|
142
|
+
@dispatch_failure_stats = RightSupport::Stats::Activity.new
|
143
|
+
@exception_stats = RightSupport::Stats::Exceptions.new(@agent)
|
245
144
|
true
|
246
145
|
end
|
247
146
|
|
147
|
+
# Determine if request TTL has expired
|
148
|
+
#
|
149
|
+
# === Parameters
|
150
|
+
# request(Push|Request):: Request to be checked
|
151
|
+
# method(String):: Actor method requested to be performed
|
152
|
+
#
|
153
|
+
# === Return
|
154
|
+
# (OperationResult|nil):: Error result if expired, otherwise nil
|
155
|
+
def expired?(request, method)
|
156
|
+
if (expires_at = request.expires_at) && expires_at > 0 && (now = Time.now.to_i) >= expires_at
|
157
|
+
@reject_stats.update("expired (#{method})")
|
158
|
+
Log.info("REJECT EXPIRED <#{request.token}> from #{request.from} TTL #{RightSupport::Stats.elapsed(now - expires_at)} ago")
|
159
|
+
# For agents that do not know about non-delivery, use error result
|
160
|
+
if request.recv_version < 13
|
161
|
+
OperationResult.error("Could not deliver request (#{OperationResult::TTL_EXPIRATION})")
|
162
|
+
else
|
163
|
+
OperationResult.non_delivery(OperationResult::TTL_EXPIRATION)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# Determine whether this request is a duplicate
|
169
|
+
#
|
170
|
+
# === Parameters
|
171
|
+
# request(Request|Push):: Packet containing request
|
172
|
+
# method(String):: Actor method requested to be performed
|
173
|
+
# idempotent(Boolean):: Whether this method is idempotent
|
174
|
+
#
|
175
|
+
# === Return
|
176
|
+
# (String|nil):: Messaging describing who already serviced request if it is a duplicate, otherwise nil
|
177
|
+
def duplicate?(request, method, idempotent)
|
178
|
+
if !idempotent && @dispatched_cache
|
179
|
+
if serviced_by = @dispatched_cache.serviced_by(request.token)
|
180
|
+
from_retry = ""
|
181
|
+
else
|
182
|
+
from_retry = "retry "
|
183
|
+
request.tries.each { |t| break if serviced_by = @dispatched_cache.serviced_by(t) }
|
184
|
+
end
|
185
|
+
if serviced_by
|
186
|
+
@reject_stats.update("#{from_retry}duplicate (#{method})")
|
187
|
+
msg = "<#{request.token}> already serviced by #{serviced_by == @identity ? 'self' : serviced_by}"
|
188
|
+
Log.info("REJECT #{from_retry.upcase}DUP #{msg}")
|
189
|
+
msg
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# Use request type to route request to actor and an associated method
|
195
|
+
#
|
196
|
+
# === Parameters
|
197
|
+
# request(Push|Request):: Packet containing request
|
198
|
+
#
|
199
|
+
# === Return
|
200
|
+
# (Array):: Actor name, method name, and whether method is idempotent
|
201
|
+
#
|
202
|
+
# === Raise
|
203
|
+
# InvalidRequestType:: If the request cannot be routed to an actor
|
204
|
+
def route(request)
|
205
|
+
prefix, method = request.type.split('/')[1..-1]
|
206
|
+
method ||= :index
|
207
|
+
method = method.to_sym
|
208
|
+
actor = @registry.actor_for(prefix)
|
209
|
+
if actor.nil? || !actor.respond_to?(method)
|
210
|
+
raise InvalidRequestType.new("Unknown actor or method for dispatching request <#{request.token}> of type #{request.type}")
|
211
|
+
end
|
212
|
+
[actor, method, actor.class.idempotent?(method)]
|
213
|
+
end
|
214
|
+
|
215
|
+
# Perform requested action
|
216
|
+
#
|
217
|
+
# === Parameters
|
218
|
+
# request(Push|Request):: Packet containing request
|
219
|
+
# token(String):: Unique identity token for request
|
220
|
+
# method(String):: Actor method requested to be performed
|
221
|
+
# idempotent(Boolean):: Whether this method is idempotent
|
222
|
+
#
|
223
|
+
# === Return
|
224
|
+
# (OperationResult):: Result from performing a request
|
225
|
+
def perform(request, actor, method, idempotent)
|
226
|
+
@dispatched_cache.store(request.token) if @dispatched_cache && !idempotent
|
227
|
+
if actor.method(method).arity.abs == 1
|
228
|
+
actor.__send__(method, request.payload)
|
229
|
+
else
|
230
|
+
actor.__send__(method, request.payload, request)
|
231
|
+
end
|
232
|
+
rescue Exception => e
|
233
|
+
@dispatch_failure_stats.update("#{request.type}->#{e.class.name}")
|
234
|
+
OperationResult.error(handle_exception(actor, method, request, e))
|
235
|
+
end
|
236
|
+
|
248
237
|
# Handle exception by logging it, calling the actors exception callback method,
|
249
238
|
# and gathering exception statistics
|
250
239
|
#
|
@@ -268,10 +257,10 @@ module RightScale
|
|
268
257
|
actor.instance_exec(method, request, exception, &actor.class.exception_callback)
|
269
258
|
end
|
270
259
|
end
|
271
|
-
@
|
260
|
+
@exception_stats.track(request.type, exception)
|
272
261
|
rescue Exception => e
|
273
262
|
Log.error("Failed handling error for #{request.type}", e, :trace)
|
274
|
-
@
|
263
|
+
@exception_stats.track(request.type, e) rescue nil
|
275
264
|
end
|
276
265
|
Log.format(error, exception)
|
277
266
|
end
|
data/lib/right_agent/pid_file.rb
CHANGED
@@ -56,7 +56,7 @@ module RightScale
|
|
56
56
|
if process_running?(pid)
|
57
57
|
raise AlreadyRunning.new("#{@pid_file} already exists and process is running (pid: #{pid})")
|
58
58
|
else
|
59
|
-
Log.info
|
59
|
+
Log.info("Removing stale pid file: #{@pid_file}")
|
60
60
|
remove
|
61
61
|
end
|
62
62
|
end
|
data/lib/right_agent/platform.rb
CHANGED
@@ -250,6 +250,20 @@ module RightScale
|
|
250
250
|
platform_service(:installer)
|
251
251
|
end
|
252
252
|
|
253
|
+
# Determines which cloud we're on by the cheap but simple expedient of
|
254
|
+
# reading the RightScale cloud file
|
255
|
+
def resolve_cloud_type
|
256
|
+
cloud_type = read_cloud_file
|
257
|
+
@ec2 = false
|
258
|
+
@rackspace = false
|
259
|
+
@eucalyptus = false
|
260
|
+
case cloud_type
|
261
|
+
when 'ec2' then @ec2 = true
|
262
|
+
when 'rackspace' then @rackspace = true
|
263
|
+
when 'eucalyptus' then @eucalyptus = true
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
253
267
|
private
|
254
268
|
|
255
269
|
# Load platform specific implementation
|
@@ -285,20 +299,6 @@ module RightScale
|
|
285
299
|
require File.expand_path(File.join(File.dirname(__FILE__), 'platform', 'windows'))
|
286
300
|
end
|
287
301
|
|
288
|
-
# Determines which cloud we're on by the cheap but simple expedient of
|
289
|
-
# reading the RightScale cloud file
|
290
|
-
def resolve_cloud_type
|
291
|
-
cloud_type = read_cloud_file
|
292
|
-
@ec2 = false
|
293
|
-
@rackspace = false
|
294
|
-
@eucalyptus = false
|
295
|
-
case cloud_type
|
296
|
-
when 'ec2' then @ec2 = true
|
297
|
-
when 'rackspace' then @rackspace = true
|
298
|
-
when 'eucalyptus' then @eucalyptus = true
|
299
|
-
end
|
300
|
-
end
|
301
|
-
|
302
302
|
# Reads the RightScale cloud file and returns its contents
|
303
303
|
def read_cloud_file
|
304
304
|
File.read(File.join(self.filesystem.right_scale_state_dir, 'cloud')) rescue nil
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# === Synopsis:
|
2
|
-
# RightScale RightAgent Controller (rnac) - (c) 2009-
|
2
|
+
# RightScale RightAgent Controller (rnac) - (c) 2009-2012 RightScale Inc
|
3
3
|
#
|
4
4
|
# rnac is a command line tool for managing a RightAgent
|
5
5
|
#
|
@@ -85,12 +85,10 @@ module RightScale
|
|
85
85
|
|
86
86
|
FORCED_OPTIONS =
|
87
87
|
{
|
88
|
-
:threadpool_size => 1
|
89
88
|
}
|
90
89
|
|
91
90
|
DEFAULT_OPTIONS =
|
92
91
|
{
|
93
|
-
:single_threaded => true,
|
94
92
|
:log_dir => Platform.filesystem.log_dir,
|
95
93
|
:daemonize => true
|
96
94
|
}
|
@@ -521,7 +519,7 @@ module RightScale
|
|
521
519
|
end # RightScale
|
522
520
|
|
523
521
|
#
|
524
|
-
# Copyright (c) 2009-
|
522
|
+
# Copyright (c) 2009-2012 RightScale Inc
|
525
523
|
#
|
526
524
|
# Permission is hereby granted, free of charge, to any person obtaining
|
527
525
|
# a copy of this software and associated documentation files (the
|