right_agent 2.2.1 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/lib/right_agent.rb +1 -0
  3. data/lib/right_agent/actor.rb +0 -28
  4. data/lib/right_agent/actors/agent_manager.rb +20 -18
  5. data/lib/right_agent/agent.rb +69 -87
  6. data/lib/right_agent/agent_tag_manager.rb +1 -1
  7. data/lib/right_agent/clients/api_client.rb +0 -1
  8. data/lib/right_agent/clients/auth_client.rb +2 -6
  9. data/lib/right_agent/clients/balanced_http_client.rb +2 -2
  10. data/lib/right_agent/clients/base_retry_client.rb +12 -19
  11. data/lib/right_agent/clients/right_http_client.rb +1 -5
  12. data/lib/right_agent/clients/router_client.rb +8 -15
  13. data/lib/right_agent/command/command_parser.rb +3 -3
  14. data/lib/right_agent/command/command_runner.rb +1 -1
  15. data/lib/right_agent/connectivity_checker.rb +7 -11
  16. data/lib/right_agent/dispatcher.rb +7 -42
  17. data/lib/right_agent/enrollment_result.rb +2 -2
  18. data/lib/right_agent/error_tracker.rb +202 -0
  19. data/lib/right_agent/log.rb +0 -2
  20. data/lib/right_agent/packets.rb +1 -1
  21. data/lib/right_agent/pending_requests.rb +10 -4
  22. data/lib/right_agent/pid_file.rb +3 -3
  23. data/lib/right_agent/protocol_version_mixin.rb +3 -3
  24. data/lib/right_agent/scripts/agent_deployer.rb +13 -1
  25. data/lib/right_agent/sender.rb +14 -30
  26. data/lib/right_agent/serialize/secure_serializer.rb +4 -4
  27. data/right_agent.gemspec +2 -2
  28. data/spec/agent_spec.rb +5 -5
  29. data/spec/clients/auth_client_spec.rb +1 -1
  30. data/spec/clients/balanced_http_client_spec.rb +4 -2
  31. data/spec/clients/base_retry_client_spec.rb +5 -6
  32. data/spec/clients/router_client_spec.rb +1 -4
  33. data/spec/dispatcher_spec.rb +6 -55
  34. data/spec/error_tracker_spec.rb +293 -0
  35. data/spec/pending_requests_spec.rb +2 -2
  36. data/spec/sender_spec.rb +3 -3
  37. data/spec/spec_helper.rb +4 -2
  38. metadata +33 -66
@@ -185,7 +185,7 @@ module RightScale
185
185
  request = RightScale::RetryableRequest.new("/router/query_tags", payload, request_options)
186
186
  request.callback { |result| yield raw ? request.raw_response : result }
187
187
  request.errback do |message|
188
- Log.error("Failed to query tags (#{message})")
188
+ ErrorTracker.log(self, "Failed to query tags (#{message})")
189
189
  yield((raw ? request.raw_response : nil) || message)
190
190
  end
191
191
  request.run
@@ -83,7 +83,6 @@ module RightScale
83
83
  # @option options [Array] :retry_intervals between successive retries; defaults to DEFAULT_RETRY_INTERVALS
84
84
  # @option options [Boolean] :retry_enabled for requests that fail to connect or that return a retry result
85
85
  # @option options [Numeric] :reconnect_interval for reconnect attempts after lose connectivity
86
- # @option options [Proc] :exception_callback for unexpected exceptions
87
86
  #
88
87
  # @raise [ArgumentError] auth client does not support this client type
89
88
  def initialize(auth_client, options)
@@ -175,7 +175,6 @@ module RightScale
175
175
  #
176
176
  # @return [Hash] current statistics
177
177
  # [Hash, NilClass] "state" Activity stats or nil if none
178
- # [Hash, NilClass] "exceptions" Exceptions stats or nil if none
179
178
  def stats(reset = false)
180
179
  stats = {}
181
180
  @stats.each { |k, v| stats[k] = v.all }
@@ -189,9 +188,7 @@ module RightScale
189
188
  #
190
189
  # @return [TrueClass] always true
191
190
  def reset_stats
192
- @stats = {
193
- "state" => RightSupport::Stats::Activity.new,
194
- "exceptions" => RightSupport::Stats::Exceptions.new(agent = nil, @exception_callback)}
191
+ @stats = {"state" => RightSupport::Stats::Activity.new}
195
192
  true
196
193
  end
197
194
 
@@ -246,8 +243,7 @@ module RightScale
246
243
  begin
247
244
  callback.call(:auth, @state)
248
245
  rescue StandardError => e
249
- Log.error("Failed status callback", e)
250
- @stats["exceptions"].track("status", e)
246
+ ErrorTracker.log(self, "Failed status callback", e, nil, :caller)
251
247
  end
252
248
  end
253
249
  end
@@ -178,7 +178,7 @@ module RightScale
178
178
  e2 = HttpExceptions.convert(e)
179
179
  log_failure(used[:host], path, params, filter, request_uuid, started_at, e2)
180
180
  raise e2
181
- rescue Exception => e
181
+ rescue StandardError => e
182
182
  log_failure(used[:host], path, params, filter, request_uuid, started_at, e)
183
183
  raise
184
184
  end
@@ -345,7 +345,7 @@ module RightScale
345
345
  def log_failure(host, path, params, filter, request_uuid, started_at, exception)
346
346
  code = exception.respond_to?(:http_code) ? exception.http_code : "nil"
347
347
  duration = "%.0fms" % ((Time.now - started_at) * 1000)
348
- Log.error("Failed <#{request_uuid}> in #{duration} | #{code} " + log_text(path, params, filter, host, exception))
348
+ ErrorTracker.log(self, "Failed <#{request_uuid}> in #{duration} | #{code} " + log_text(path, params, filter, host, exception))
349
349
  true
350
350
  end
351
351
 
@@ -77,7 +77,6 @@ module RightScale
77
77
  # EM::HttpRequest and fibers instead of RestClient; requests remain synchronous
78
78
  # @option options [Array] :filter_params symbols or strings for names of request parameters
79
79
  # whose values are to be hidden when logging; can be augmented on individual requests
80
- # @option options [Proc] :exception_callback for unexpected exceptions
81
80
  #
82
81
  # @return [Boolean] whether currently connected
83
82
  #
@@ -161,7 +160,6 @@ module RightScale
161
160
  # [Hash, NilClass] "request sent" Activity stats or nil if none
162
161
  # [Float, NilClass] "response time" average number of seconds to respond to a request or nil if none
163
162
  # [Hash, NilClass] "state" Activity stats or nil if none
164
- # [Hash, NilClass] "exceptions" Exceptions stats or nil if none
165
163
  def stats(reset = false)
166
164
  stats = {}
167
165
  @stats.each { |k, v| stats[k] = v.all }
@@ -180,8 +178,7 @@ module RightScale
180
178
  "reconnects" => RightSupport::Stats::Activity.new,
181
179
  "request failures" => RightSupport::Stats::Activity.new,
182
180
  "requests sent" => RightSupport::Stats::Activity.new,
183
- "state" => RightSupport::Stats::Activity.new,
184
- "exceptions" => RightSupport::Stats::Exceptions.new(agent = nil, @options[:exception_callback]) }
181
+ "state" => RightSupport::Stats::Activity.new }
185
182
  true
186
183
  end
187
184
 
@@ -212,8 +209,7 @@ module RightScale
212
209
  begin
213
210
  callback.call(@type, @state)
214
211
  rescue StandardError => e
215
- Log.error("Failed status callback", e)
216
- @stats["exceptions"].track("status", e)
212
+ ErrorTracker.log(self, "Failed status callback", e, nil, :caller)
217
213
  end
218
214
  end
219
215
  reconnect if @state == :disconnected
@@ -248,9 +244,8 @@ module RightScale
248
244
  def close_http_client(reason)
249
245
  @http_client.close(reason) if @http_client
250
246
  true
251
- rescue Exception => e
252
- Log.error("Failed closing connection", e, :trace)
253
- @stats["exceptions"].track("status", e)
247
+ rescue StandardError => e
248
+ ErrorTracker.log(self, "Failed closing connection", e)
254
249
  false
255
250
  end
256
251
 
@@ -271,11 +266,10 @@ module RightScale
271
266
  @http_client.check_health
272
267
  self.state = :connected
273
268
  rescue BalancedHttpClient::NotResponding => e
274
- Log.error("Failed #{@options[:server_name]} health check", e.nested_exception)
269
+ ErrorTracker.log(self, "Failed #{@options[:server_name]} health check", e.nested_exception)
275
270
  self.state = :disconnected
276
- rescue Exception => e
277
- Log.error("Failed #{@options[:server_name]} health check", e)
278
- @stats["exceptions"].track("check health", e)
271
+ rescue StandardError => e
272
+ ErrorTracker.log(self, "Failed #{@options[:server_name]} health check", e, nil, :caller)
279
273
  self.state = :disconnected
280
274
  end
281
275
  end
@@ -298,9 +292,8 @@ module RightScale
298
292
  @reconnect_timer = @reconnecting = nil
299
293
  end
300
294
  rescue Exception => e
301
- Log.error("Failed #{@options[:server_name]} reconnect", e)
295
+ ErrorTracker.log(self, "Failed #{@options[:server_name]} reconnect", e, nil, :caller)
302
296
  @stats["reconnects"].update("failure")
303
- @stats["exceptions"].track("reconnect", e)
304
297
  self.state = :disconnected
305
298
  end
306
299
  @reconnect_timer.interval = @options[:reconnect_interval] if @reconnect_timer
@@ -472,8 +465,8 @@ module RightScale
472
465
  @stats["request failures"].update("#{type} - retry")
473
466
  raise Exceptions::RetryableError.new(retry_result.http_body, retry_result)
474
467
  else
475
- Log.error("Retrying #{type} request <#{request_uuid}> in #{interval} seconds " +
476
- "in response to retryable error (#{retry_result.http_body})")
468
+ ErrorTracker.log(self, "Retrying #{type} request <#{request_uuid}> in #{interval} seconds " +
469
+ "in response to retryable error (#{retry_result.http_body})")
477
470
  wait(interval)
478
471
  end
479
472
  # Change request_uuid so that retried request not rejected as duplicate
@@ -505,8 +498,8 @@ module RightScale
505
498
  self.state = :disconnected
506
499
  raise Exceptions::ConnectivityFailure.new(not_responding.message + " after #{attempts} attempts")
507
500
  else
508
- Log.error("Retrying #{type} request <#{request_uuid}> in #{interval} seconds " +
509
- "in response to routing failure (#{BalancedHttpClient.exception_text(not_responding)})")
501
+ ErrorTracker.log(self, "Retrying #{type} request <#{request_uuid}> in #{interval} seconds " +
502
+ "in response to routing failure (#{BalancedHttpClient.exception_text(not_responding)})")
510
503
  wait(interval)
511
504
  end
512
505
  true
@@ -51,10 +51,6 @@ module RightScale
51
51
  # @option options [Boolean] :long_polling_only never attempt to create a WebSocket, always long-polling instead
52
52
  # @option options [Array] :filter_params symbols or strings for names of request parameters
53
53
  # whose values are to be hidden when logging
54
- # @option options [Proc] :exception_callback for unexpected exceptions with following parameters:
55
- # [Exception] exception raised
56
- # [Packet, NilClass] packet being processed
57
- # [Agent, NilClass] agent in which exception occurred
58
54
  #
59
55
  # @return [TrueClass] always true
60
56
  #
@@ -275,7 +271,7 @@ module RightScale
275
271
  begin
276
272
  callback.call(type, state)
277
273
  rescue RuntimeError => e
278
- Log.error("Failed status callback", e)
274
+ ErrorTracker.log(self, "Failed status callback", e, nil, :caller)
279
275
  end
280
276
  end
281
277
  @status
@@ -88,7 +88,6 @@ module RightScale
88
88
  # @option options [Numeric] :reconnect_interval for reconnect attempts after lose connectivity
89
89
  # @option options [Boolean] :non_blocking i/o is to be used for HTTP requests by applying
90
90
  # EM::HttpRequest and fibers instead of RestClient; requests remain synchronous
91
- # @option options [Proc] :exception_callback for unexpected exceptions
92
91
  #
93
92
  # @raise [ArgumentError] auth client does not support this client type
94
93
  def initialize(auth_client, options)
@@ -262,7 +261,6 @@ module RightScale
262
261
  # [Hash, NilClass] "request failures" Activity stats or nil if none
263
262
  # [Hash, NilClass] "request sent" Activity stats or nil if none
264
263
  # [Float, NilClass] "response time" average number of seconds to respond to a request or nil if none
265
- # [Hash, NilClass] "exceptions" Exceptions stats or nil if none
266
264
  def stats(reset = false)
267
265
  events = @stats["events"].all
268
266
  stats = super(reset)
@@ -337,11 +335,10 @@ module RightScale
337
335
  end
338
336
  @listen_failures = 0
339
337
  rescue Exception => e
340
- Log.error("Failed to listen", e, :trace)
341
- @stats["exceptions"].track("listen", e)
338
+ ErrorTracker.log(self, "Failed to listen", e)
342
339
  @listen_failures += 1
343
340
  if @listen_failures > MAX_LISTEN_FAILURES
344
- Log.error("Exceeded maximum repeated listen failures (#{MAX_LISTEN_FAILURES}), stopping listening")
341
+ ErrorTracker.log(self, "Exceeded maximum repeated listen failures (#{MAX_LISTEN_FAILURES}), stopping listening")
345
342
  @listen_state = :cancel
346
343
  self.state = :failed
347
344
  return false
@@ -440,8 +437,7 @@ module RightScale
440
437
  connect(routing_keys, &handler)
441
438
  update_listen_state(:check, 1)
442
439
  rescue Exception => e
443
- Log.error("Failed creating WebSocket", e)
444
- @stats["exceptions"].track("websocket", e)
440
+ ErrorTracker.log(self, "Failed creating WebSocket", e, nil, :caller)
445
441
  backoff_connect_interval
446
442
  update_listen_state(:long_poll)
447
443
  end
@@ -477,7 +473,7 @@ module RightScale
477
473
  @websocket = Faye::WebSocket::Client.new(url.to_s, protocols = nil, options)
478
474
 
479
475
  @websocket.onerror = lambda do |event|
480
- Log.error("WebSocket error (#{event.data})") if event.data
476
+ ErrorTracker.log(self, "WebSocket error (#{event.data})") if event.data
481
477
  end
482
478
 
483
479
  @websocket.onclose = lambda do |event|
@@ -488,8 +484,7 @@ module RightScale
488
484
  msg << ((event.reason.nil? || event.reason.empty?) ? ")" : ": #{event.reason})")
489
485
  Log.info(msg)
490
486
  rescue Exception => e
491
- Log.error("Failed closing WebSocket", e, :trace)
492
- @stats["exceptions"].track("event", e)
487
+ ErrorTracker.log(self, "Failed closing WebSocket", e)
493
488
  end
494
489
  @websocket = nil
495
490
  end
@@ -508,8 +503,7 @@ module RightScale
508
503
  handler.call(event)
509
504
  @communicated_callbacks.each { |callback| callback.call } if @communicated_callbacks
510
505
  rescue Exception => e
511
- Log.error("Failed handling WebSocket event", e, :trace)
512
- @stats["exceptions"].track("event", e)
506
+ ErrorTracker.log(self, "Failed handling WebSocket event", e)
513
507
  end
514
508
  end
515
509
 
@@ -596,6 +590,7 @@ module RightScale
596
590
  end
597
591
 
598
592
  # Process result from long-polling attempt
593
+ # Not necessary to log failure since should already have been done by underlying HTTP client
599
594
  #
600
595
  # @param [Array, NilClass] result from long-polling attempt
601
596
  #
@@ -603,12 +598,10 @@ module RightScale
603
598
  def process_long_poll(result)
604
599
  case result
605
600
  when Exceptions::Unauthorized, Exceptions::ConnectivityFailure, Exceptions::RetryableError, Exceptions::InternalServerError
606
- Log.error("Failed long-polling", result, :no_trace)
607
601
  update_listen_state(:choose, backoff_reconnect_interval)
608
602
  result = nil
609
603
  when Exception
610
- Log.error("Failed long-polling", result, :trace)
611
- @stats["exceptions"].track("long-polling", result)
604
+ ErrorTracker.track(self, result)
612
605
  update_listen_state(:choose, backoff_reconnect_interval)
613
606
  result = nil
614
607
  else
@@ -51,12 +51,12 @@ module RightScale
51
51
  def parse_chunk(chunk)
52
52
  @buildup << chunk
53
53
  chunks = @buildup.split(CommandSerializer::SEPARATOR, -1)
54
- if do_call = chunks.size > 1
54
+ if (do_call = chunks.size > 1)
55
55
  commands = []
56
56
  (0..chunks.size - 2).each do |i|
57
57
  begin
58
58
  commands << CommandSerializer.load(chunks[i])
59
- rescue Exception => e
59
+ rescue StandardError => e
60
60
  # log any exceptions caused by serializing individual chunks instead
61
61
  # of halting EM. each command is discrete so we need to keep trying
62
62
  # so long as there are more commands to process (although subsequent
@@ -77,7 +77,7 @@ module RightScale
77
77
  @buildup = chunks.last
78
78
  end
79
79
  do_call
80
- rescue Exception => e
80
+ rescue StandardError => e
81
81
  # log any other exceptions instead of halting EM.
82
82
  Log.error("Failed parsing command chunk", e, :trace)
83
83
  end
@@ -79,7 +79,7 @@ module RightScale
79
79
  Log.error("Invalid cookie used by command protocol client (#{cmd_cookie})")
80
80
  end
81
81
  rescue Exception => e
82
- Log.warning("Command failed (#{e.message}) at\n#{e.backtrace.join("\n")}")
82
+ Log.error("Command failed", e, :trace)
83
83
  end
84
84
  end
85
85
 
@@ -38,13 +38,12 @@ module RightScale
38
38
  # Timer while waiting for RightNet router ping response
39
39
  attr_accessor :ping_timer
40
40
 
41
- def initialize(sender, check_interval, ping_stats, exception_stats)
41
+ def initialize(sender, check_interval, ping_stats)
42
42
  @sender = sender
43
43
  @check_interval = check_interval
44
44
  @ping_timeouts = {}
45
45
  @ping_timer = nil
46
46
  @ping_stats = ping_stats
47
- @exception_stats = exception_stats
48
47
  @last_received = Time.now
49
48
  @message_received_callbacks = []
50
49
  restart_inactivity_timer if @check_interval > 0
@@ -98,17 +97,16 @@ module RightScale
98
97
  @ping_timer = nil
99
98
  @ping_timeouts[@ping_id] = (@ping_timeouts[@ping_id] || 0) + 1
100
99
  if @ping_timeouts[@ping_id] >= max_ping_timeouts
101
- Log.error("Mapper ping via broker #{@ping_id} timed out after #{PING_TIMEOUT} seconds and now " +
102
- "reached maximum of #{max_ping_timeouts} timeout#{max_ping_timeouts > 1 ? 's' : ''}, " +
103
- "attempting to reconnect")
100
+ ErrorTracker.log(self, "Mapper ping via broker #{@ping_id} timed out after #{PING_TIMEOUT} seconds and now " +
101
+ "reached maximum of #{max_ping_timeouts} timeout#{max_ping_timeouts > 1 ? 's' : ''}, " +
102
+ "attempting to reconnect")
104
103
  host, port, index, priority = @sender.client.identity_parts(@ping_id)
105
104
  @sender.agent.connect(host, port, index, priority, force = true)
106
105
  else
107
106
  Log.warning("Mapper ping via broker #{@ping_id} timed out after #{PING_TIMEOUT} seconds")
108
107
  end
109
108
  rescue Exception => e
110
- Log.error("Failed to reconnect to broker #{@ping_id}", e, :trace)
111
- @exception_stats.track("ping timeout", e)
109
+ ErrorTracker.log(self, "Failed to reconnect to broker #{@ping_id}", e)
112
110
  end
113
111
  else
114
112
  @ping_timer = nil
@@ -125,8 +123,7 @@ module RightScale
125
123
  @ping_id = nil
126
124
  end
127
125
  rescue Exception => e
128
- Log.error("Failed to cancel router ping", e, :trace)
129
- @exception_stats.track("cancel ping", e)
126
+ ErrorTracker.log(self, "Failed to cancel router ping", e)
130
127
  end
131
128
  end
132
129
  request = Request.new("/router/ping", nil, {:from => @sender.identity, :token => AgentIdentity.generate})
@@ -167,8 +164,7 @@ module RightScale
167
164
  begin
168
165
  check(id = nil, max_ping_timeouts = 1)
169
166
  rescue Exception => e
170
- Log.error("Failed connectivity check", e, :trace)
171
- @exception_stats.track("check connectivity", e)
167
+ ErrorTracker.log(self, "Failed connectivity check", e)
172
168
  end
173
169
  end
174
170
  true
@@ -27,8 +27,8 @@ module RightScale
27
27
 
28
28
  include ProtocolVersionMixin
29
29
 
30
- class InvalidRequestType < Exception; end
31
- class DuplicateRequest < Exception; end
30
+ class InvalidRequestType < RuntimeError; end
31
+ class DuplicateRequest < RuntimeError; end
32
32
 
33
33
  # (ActorRegistry) Registry for actors
34
34
  attr_reader :registry
@@ -88,7 +88,7 @@ module RightScale
88
88
  actor, method, idempotent = route(request)
89
89
  received_at = @request_stats.update(method, (token if request.is_a?(Request)))
90
90
  if (dup = duplicate?(request, method, idempotent))
91
- raise DuplicateRequest.new(dup)
91
+ raise DuplicateRequest, dup
92
92
  end
93
93
  unless (result = expired?(request, method))
94
94
  result = perform(request, actor, method, idempotent)
@@ -110,9 +110,6 @@ module RightScale
110
110
  # or nil if empty
111
111
  # "dispatch failures"(Hash|nil):: Dispatch failure activity stats with keys "total", "percent", "last", and "rate"
112
112
  # with percentage breakdown per failure type, or nil if none
113
- # "exceptions"(Hash|nil):: Exceptions raised per category, or nil if none
114
- # "total"(Integer):: Total for category
115
- # "recent"(Array):: Most recent as a hash of "count", "type", "message", "when", and "where"
116
113
  # "rejects"(Hash|nil):: Request reject activity stats with keys "total", "percent", "last", and "rate"
117
114
  # with percentage breakdown per reason ("duplicate (<method>)", "retry duplicate (<method>)", or
118
115
  # "stale (<method>)"), or nil if none
@@ -123,7 +120,6 @@ module RightScale
123
120
  stats = {
124
121
  "dispatched cache" => (@dispatched_cache.stats if @dispatched_cache),
125
122
  "dispatch failures" => @dispatch_failure_stats.all,
126
- "exceptions" => @exception_stats.stats,
127
123
  "rejects" => @reject_stats.all,
128
124
  "requests" => @request_stats.all,
129
125
  "response time" => @request_stats.avg_duration
@@ -142,7 +138,6 @@ module RightScale
142
138
  @reject_stats = RightSupport::Stats::Activity.new
143
139
  @request_stats = RightSupport::Stats::Activity.new
144
140
  @dispatch_failure_stats = RightSupport::Stats::Activity.new
145
- @exception_stats = RightSupport::Stats::Exceptions.new(@agent, @agent.exception_callback)
146
141
  true
147
142
  end
148
143
 
@@ -209,7 +204,7 @@ module RightScale
209
204
  method = method.to_sym
210
205
  actor = @registry.actor_for(prefix)
211
206
  if actor.nil? || !actor.respond_to?(method)
212
- raise InvalidRequestType.new("Unknown actor or method for dispatching request <#{request.token}> of type #{request.type}")
207
+ raise InvalidRequestType, "Unknown actor or method for dispatching request <#{request.token}> of type #{request.type}"
213
208
  end
214
209
  [actor, method, actor.class.idempotent?(method)]
215
210
  end
@@ -231,40 +226,10 @@ module RightScale
231
226
  else
232
227
  actor.send(method, request.payload, request)
233
228
  end
234
- rescue Exception => e
229
+ rescue StandardError => e
230
+ ErrorTracker.log(self, "Failed dispatching #{request.trace}", e, request)
235
231
  @dispatch_failure_stats.update("#{request.type}->#{e.class.name}")
236
- OperationResult.error(handle_exception(actor, method, request, e))
237
- end
238
-
239
- # Handle exception by logging it, calling the actors exception callback method,
240
- # and gathering exception statistics
241
- #
242
- # === Parameters
243
- # actor(Actor):: Actor that failed to process request
244
- # method(Symbol):: Name of actor method being dispatched to
245
- # request(Packet):: Packet that dispatcher is acting upon
246
- # exception(Exception):: Exception that was raised
247
- #
248
- # === Return
249
- # (String):: Error description for this exception
250
- def handle_exception(actor, method, request, exception)
251
- error = "Could not handle #{request.type} request"
252
- Log.error(error, exception, :trace)
253
- begin
254
- if actor && actor.class.exception_callback
255
- case actor.class.exception_callback
256
- when Symbol, String
257
- actor.send(actor.class.exception_callback, method, request, exception)
258
- when Proc
259
- actor.instance_exec(method, request, exception, &actor.class.exception_callback)
260
- end
261
- end
262
- @exception_stats.track(request.type, exception)
263
- rescue Exception => e
264
- Log.error("Failed handling error for #{request.type}", e, :trace)
265
- @exception_stats.track(request.type, e) rescue nil
266
- end
267
- Log.format(error, exception)
232
+ OperationResult.error("Could not handle #{request.type} request", e)
268
233
  end
269
234
 
270
235
  end # Dispatcher