Exceptions Use/Handling in Conductor

Martyn Taylor mtaylor at redhat.com
Mon Dec 5 11:17:44 UTC 2011


Gents,

Our current exception use/handling in conductor is less than ideal.  
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.

Cheers

Martyn

--

So, we use the below syntax in many places in conductor code.  Using 
this syntax to raise an exception is problematic:

raise "Some error occurred while trying to do something"

Why?

There is no way for conductor to interpret the cause of this exception, 
and react accordingly.

Example1: Recovery of errors

(of course this could be rewritten in a way to not use custom exception 
but is just a simple example to demonstrate the need)

    def perform_task
       case @task.name
         when "Start Instance": start_instance(@task.realms[0])
         ...
       end
    end

    def start_instance(realm)
       ...
       # Instance failed realms full
         raise "Could not start instance realms are full"
       end
    end


In the above code, perform_task calls start_instance which raises an 
exception with the user message  "the realm is full".  This then gets 
filtered up the chain and caught in the ApplicationController which logs 
the error and filters the message back to the user.

-- Using Custom Exceptions

    def perform_task(task)
       begin
         case task.name
           when "Start Instance": start_instance(task.realms[0])
           ...
         end
       rescue RealmFull => rfe
         if task.realms.size > 1
           task.realms.delete(0)
           perform_task|(task)
         else
           raise rfe
         end
       end
    end

    def start_instance(realm)
       ...
       # Instance failed realms full
         raise RealmFull.new(:message => "Could not start instance
    realms are full")
       end
    end


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.  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.

Of course you could say why not just catch all exceptions in the first 
example and react accordingly.  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...


Example2: Catching/Handle generic exceptions at the top of the chain

Once we have defined custom exceptions we can then manage them at the 
top level, categorised into particular genres.  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.  This allows us to handle all APIExceptions at 
the top level.  ApplicationController has a filter than catches all 
APIExceptions that are raised this far up the stack.  It then creates a 
proper XMLResponse, with HTTP status code, Error Code and Error Message.

You can imagine we have lots of exceptions genres, e.g. UIException.  
When application controller catches a UIException it knows it must 
display a message to the user.

ConductorException, might simply just log the exception trace and carry 
on as normal.

And so on.

--- Exception Handling

In order to add in the power of exceptions we need to all agree on a 
particular approach.

Here are 3 rules that if we stick to will let us handle exceptions more 
wisely.

1) Never Swallow Exceptions (Unless they are an expectation)

2) Try to handle the exception locally.

3) If 2 is not possible, pass the exception up the stack, (wrapping it 
into something understandable to the upstream method, if neccessary).

If everyone sticks to these 3 rules.  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.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.fedorahosted.org/pipermail/aeolus-devel/attachments/20111205/bc2f20ec/attachment.html>


More information about the aeolus-devel mailing list