geronimo-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dain Sundstrom <d...@iq80.com>
Subject Re: GBeanInstance/GBeanInstanceState eating exceptions?
Date Tue, 27 Feb 2007 01:43:18 GMT
I fixed a bug in 1.2, where the exception was being rethrown before  
it was recorded as the root cause.

-dain

On Feb 26, 2007, at 4:22 PM, David Jencks wrote:

>
> On Feb 26, 2007, at 3:33 PM, Jason Dillon wrote:
>
>> I think David Jencks added something (or was going to add  
>> something) which would provide more detail for these exceptions  
>> when run from the car-m-p.
>>
>> David, did you ever get around to adding that?  If not, is it  
>> something you can easily do?
>
> I definitely added it to trunk (2.0).  I'm not sure if it made it  
> into 1.2.
>
> thanks
> david jencks
>
>>
>> --jason
>>
>>
>> On Jan 19, 2007, at 4:20 PM, Dain Sundstrom wrote:
>>
>>> I didn't know you wanted details :)   Honestly, I have no idea  
>>> why the exception is being eaten, other than it may be expected.   
>>> The startup is asynchronous, so the start may wake up in a "not  
>>> yet ready" state.  The reason it is in the current state is  
>>> recorded in GBEanInstance.getStateReason().
>>>
>>> It is the configuration object that has decided, that it has  
>>> waited long enough and if all beans are not started it is going  
>>> to give up.  The feature was recently added, and is a big  
>>> improvement over the previous behavior of waiting forever.   
>>> Basically, the configuration attempts to get all beans started,  
>>> if they don't all start then it throws an exception stating why  
>>> some of the beans didn't start.
>>>
>>> Anyway, if you see some more information that needs to be  
>>> propagated, by all means add it, just be careful, that you aren't  
>>> wiping out relevant information with irrelevant info.
>>>
>>> -dain
>>>
>>> On Jan 19, 2007, at 2:05 PM, Jason Dillon wrote:
>>>
>>>> Where are the methods to pass back failure information from  
>>>> GBeanInstanceState to GBeanInstance (and so on) ?
>>>>
>>>> I don't see anything like getFailureReason() or anything similar.
>>>>
>>>> How is one supposed to expose the MissingDependencyException  
>>>> that is thrown in GBeanInstanceState.attemptFullStart(), which  
>>>> occurs when calling gbeanInstance.createInstance() and is then  
>>>> caught and eaten?
>>>>
>>>> I need to propagate this exception detail back further to the  
>>>> component that asked for the component to be loaded, and attach  
>>>> the detail to the failure exception that is thrown when we ask a  
>>>> configuration to load.
>>>>
>>>> What is the api to store and retrieve exceptions later that you  
>>>> mention?
>>>>
>>>> --jason
>>>>
>>>>
>>>> On Jan 17, 2007, at 10:40 PM, Dain Sundstrom wrote:
>>>>
>>>>> I'm not going to try to justify the design, but I'll explain it...
>>>>>
>>>>> The lifecycle method don't necessarily result in the bean fully  
>>>>> completing a state change.  The bean may enter a transition  
>>>>> state like starting or stopping and wait there for a resource  
>>>>> to become available.  Really, they just initiate  a lifecycle  
>>>>> change that will complete at a later time.  If the method were  
>>>>> to throw an exception it would be completely random if it  
>>>>> "worked" or not.  Therefore, the methods don't throw exceptions  
>>>>> and then are supposed to store the exception so it can be  
>>>>> retrieved later.
>>>>>
>>>>> The key is that most gbeans are started by the configuration  
>>>>> and the configuration will gather any failures and throw a  
>>>>> single exception containing all the problems.
>>>>>
>>>>> Now if there are places problems occurs and the exceptions  
>>>>> aren't saved, it is a bug.
>>>>>
>>>>> -dain
>>>>>
>>>>> On Jan 17, 2007, at 2:06 PM, Jason Dillon wrote:
>>>>>
>>>>>> Why do GBeanInstance/GBeanInstanceState eat exceptions instead  
>>>>>> of throwing them?
>>>>>>
>>>>>> This seems to be a common pattern with GBeans, where they  
>>>>>> don't propagate the exception detail.  I was just looking at  
>>>>>> GBeanInstance.start(), but looks like stop() and other methods  
>>>>>> have the same basic issues.
>>>>>>
>>>>>> The lack of detail being propagated results in build failures  
>>>>>> like:
>>>>>>
>>>>>> <snip>
>>>>>> Configuration gbean failed to start  
>>>>>> org.apache.geronimo.configs/openejb/2.0-SNAPSHOT/car
>>>>>> </snip>
>>>>>>
>>>>>> But they show no detail as to why they failed.  This one  
>>>>>> happens to be caused by:
>>>>>>
>>>>>> <snip>
>>>>>> org.apache.geronimo.kernel.repository.MissingDependencyException:

>>>>>>  Unable to resolve dependency org.apache.openejb/openejb- 
>>>>>> loader//jar
>>>>>>         at  
>>>>>> org.apache.geronimo.kernel.repository.DefaultArtifactResolver.res

>>>>>> olveInClassLoader(DefaultArtifactResolver.java:123)
>>>>>>         at  
>>>>>> org.apache.geronimo.kernel.repository.DefaultArtifactResolver$ 
>>>>>> $FastClassByCGLIB$$e847b746.invoke(<generated>)
>>>>>>         at net.sf.cglib.reflect.FastMethod.invoke 
>>>>>> (FastMethod.java:53)
>>>>>> ...
>>>>>> </snip>
>>>>>>
>>>>>> But you would never know that unless you hack up the  
>>>>>> GBeanInstanceState with printlns or something.  There is some  
>>>>>> logging which is done, but that is getting lost due to  
>>>>>> mismatch in log4j and maven logging systems.  I thought I had  
>>>>>> a bridge setup to handle this, but it appears to have been  
>>>>>> broken for sometime.  But aside from the logging issue, I  
>>>>>> think its a bigger problem that the GBean stuff is not  
>>>>>> throwing exceptions with meaningful details.
>>>>>>
>>>>>> There are other bits which look rather wrong wrt showing  
>>>>>> exception details, like:
>>>>>>
>>>>>> <snip>
>>>>>> try {
>>>>>>     kernel.startRecursiveGBean(dependent);
>>>>>> } catch (GBeanNotFoundException e) {
>>>>>>     // this is ok the gbean died before we could start it
>>>>>> } catch (Exception e) {
>>>>>>     // there is something wrong with this gbean... skip it
>>>>>> }
>>>>>> </snip>
>>>>>>
>>>>>> There is no log here at all... this exception just gets  
>>>>>> swallowed up.
>>>>>>
>>>>>> This also looks fishy:
>>>>>>
>>>>>> <snip>
>>>>>> try {
>>>>>>     // try to create the instance
>>>>>>     if (!gbeanInstance.createInstance()) {
>>>>>>         // instance is not ready to start... this is normally  
>>>>>> caused by references
>>>>>>         // not being available, but could be because someone  
>>>>>> already started the gbean.
>>>>>>         // in another thread.  The reference will log a debug  
>>>>>> message about why
>>>>>>         // it could not start
>>>>>>         return;
>>>>>>     }
>>>>>> } catch (Throwable t) {
>>>>>>     // oops there was a problem and the gbean failed
>>>>>>     log.error("Error while starting; GBean is now in the  
>>>>>> FAILED state: abstractName=\"" + abstractName + "\"", t);
>>>>>>     setStateInstance(State.FAILED);
>>>>>>     lifecycleBroadcaster.fireFailedEvent();
>>>>>>
>>>>>>     if (t instanceof Exception) {
>>>>>>         // ignore - we only rethrow errors
>>>>>>         return;
>>>>>>     } else if (t instanceof Error) {
>>>>>>         throw (Error) t;
>>>>>>     } else {
>>>>>>         throw new Error(t);
>>>>>>     }
>>>>>> }
>>>>>>
>>>>>> // started successfully... notify everyone else
>>>>>> setStateInstance(State.RUNNING);
>>>>>> lifecycleBroadcaster.fireRunningEvent();
>>>>>> </snip>
>>>>>>
>>>>>> The catch here is actually what was handling the above  
>>>>>> MissingDependencyException, which sets the state to failed,  
>>>>>> broadcasts the event, then eats the exception, and then  
>>>>>> continues to set the state to running and broadcasts that  
>>>>>> event, which should fail on the state transition of FAILED ->
 
>>>>>> RUNNING... but we should not even be attempting that  
>>>>>> transition because of the caught exception.
>>>>>>
>>>>>> The nice comment about the createInstance() logging a DEBUG  
>>>>>> message is also odd... this failure reason really should also  
>>>>>> be propagated via an exception to allow higher-level systems  
>>>>>> to handle it as needed.  All of this exception eating is  
>>>>>> really making things much more difficult than they need to be  
>>>>>> when using the car plugin to build the server.
>>>>>>
>>>>>>  * * *
>>>>>>
>>>>>> What is the reasoning behind this behavior?  I think that we  
>>>>>> can simplify things a lot by simply throwing exceptions, as  
>>>>>> well as propagating details to layers that really need it  
>>>>>> (like the car:package goal really needs to know why the gbean  
>>>>>> failed to start so that it can communicate that to the user).
>>>>>>
>>>>>> Can someone please explain to me why these exceptions are not  
>>>>>> being thrown?
>>>>>>
>>>>>> Thanks,
>>>>>>
>>>>>> --jason
>>>>>
>>>>
>>>
>>
>


Mime
View raw message