<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    Gents,<br>
    <br>
    Our current exception use/handling in conductor is less than ideal.&nbsp;
    I've tried to highlight some of the issues here, and proposed an
    approach that I feel we should take when it comes to exceptions
    handling. Anyone with thoughts on this topic please chime in.<br>
    <br>
    Cheers<br>
    <br>
    Martyn<br>
    <br>
    --<br>
    <br>
    So, we use the below syntax in many places in conductor code.&nbsp; Using
    this syntax to raise an exception is problematic:<br>
    <br>
    raise "Some error occurred while trying to do something"<br>
    <br>
    Why?<br>
    <br>
    There is no way for conductor to interpret the cause of this
    exception, and react accordingly.<br>
    <br>
    Example1: Recovery of errors<br>
    <br>
    (of course this could be rewritten in a way to not use custom
    exception but is just a simple example to demonstrate the need)<br>
    <br>
    <blockquote>def perform_task<br>
      &nbsp; case @task.name<br>
      &nbsp;&nbsp;&nbsp; when "Start Instance": start_instance(@task.realms[0])<br>
      &nbsp;&nbsp;&nbsp; ...<br>
      &nbsp; end&nbsp; <br>
      end<br>
      <br>
      def start_instance(realm)<br>
      &nbsp; ...<br>
      &nbsp; # Instance failed realms full<br>
      &nbsp;&nbsp;&nbsp; raise "Could not start instance realms are full"<br>
      &nbsp; end<br>
      end<br>
    </blockquote>
    <br>
    In the above code, perform_task calls start_instance which raises an
    exception with the user message&nbsp; "the realm is full".&nbsp; This then
    gets filtered up the chain and caught in the ApplicationController
    which logs the error and filters the message back to the user.<br>
    <br>
    -- Using Custom Exceptions<br>
    <blockquote>def perform_task(task)<br>
      &nbsp; begin<br>
      &nbsp;&nbsp;&nbsp; case task.name<br>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; when "Start Instance": start_instance(task.realms[0])<br>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br>
      &nbsp;&nbsp;&nbsp; end<br>
      &nbsp; rescue RealmFull =&gt; rfe<br>
      &nbsp;&nbsp;&nbsp; if task.realms.size &gt; 1<br>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; task.realms.delete(0)<br>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; perform_task|(task)<br>
      &nbsp;&nbsp;&nbsp; else<br>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; raise rfe<br>
      &nbsp;&nbsp;&nbsp; end<br>
      &nbsp; end<br>
      end<br>
      <br>
      def start_instance(realm)<br>
      &nbsp; ...<br>
      &nbsp; # Instance failed realms full<br>
      &nbsp;&nbsp;&nbsp; raise RealmFull.new(:message =&gt; "Could not start instance
      realms are full")<br>
      &nbsp; end<br>
      end<br>
    </blockquote>
    <br>
    In the 2nd example, we can recover from realm full problem by
    catching the RealmFull exception, and retrying the start_instance
    with the next realm in our list until our list is exhausted.&nbsp; Once
    the realm list is exhausted there nothing more we can do at this
    point so we raise the RealmFull exception up to the next level,
    where it is then handled accordingly.<br>
    <br>
    Of course you could say why not just catch all exceptions in the
    first example and react accordingly.&nbsp; Well yes in this example you
    could do that, but imagine start_instance can fail in many places:
    realm full, hwp does not exist, ami not found etc...<br>
    <br>
    <br>
    Example2: Catching/Handle generic exceptions at the top of the chain<br>
    <br>
    Once we have defined custom exceptions we can then manage them at
    the top level, categorised into particular genres.&nbsp; An example where
    this already happens in conductor is in the API, where we have
    defined an APIException, all exceptions throw from within the API
    controllers extend this exception and all other exceptions should*
    be wrapped in an appropriate APIException.&nbsp; This allows us to handle
    all APIExceptions at the top level.&nbsp; ApplicationController has a
    filter than catches all APIExceptions that are raised this far up
    the stack.&nbsp; It then creates a proper XMLResponse, with HTTP status
    code, Error Code and Error Message.<br>
    <br>
    You can imagine we have lots of exceptions genres, e.g.
    UIException.&nbsp; When application controller catches a UIException it
    knows it must display a message to the user.<br>
    <br>
    ConductorException, might simply just log the exception trace and
    carry on as normal.<br>
    <br>
    And so on.<br>
    <br>
    --- Exception Handling<br>
    <br>
    In order to add in the power of exceptions we need to all agree on a
    particular approach.<br>
    <br>
    Here are 3 rules that if we stick to will let us handle exceptions
    more wisely.<br>
    <br>
    1) Never Swallow Exceptions (Unless they are an expectation)<br>
    <br>
    2) Try to handle the exception locally.<br>
    <br>
    3) If 2 is not possible, pass the exception up the stack, (wrapping
    it into something understandable to the upstream method, if
    neccessary).<br>
    <br>
    If everyone sticks to these 3 rules.&nbsp; Exceptions will be handled and
    recovered from in all cases possible, those that are not will
    eventually work their way up to the application controller where
    they will be handled appropriately, according to their genre.<br>
    <br>
  </body>
</html>