geronimo-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jason Dillon <ja...@planet57.com>
Subject Re: GBeanInstance/GBeanInstanceState eating exceptions?
Date Tue, 27 Feb 2007 22:23:07 GMT
Know off hand what the change revision was?  This *should* probably  
make it into 1.2 at some point...

--jason


On Feb 26, 2007, at 5:52 PM, David Jencks wrote:

> The stuff I added was mostly changing interfaces so the client  
> could access the reason, and having the client do so: I also  
> changed a bunch of places to record more info in the reason.
>
> thanks
> david jencks
>
> On Feb 26, 2007, at 5:43 PM, Dain Sundstrom wrote:
>
>> 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.MissingDependencyExceptio

>>>>>>>> n: Unable to resolve dependency org.apache.openejb/openejb-

>>>>>>>> loader//jar
>>>>>>>>         at  
>>>>>>>> org.apache.geronimo.kernel.repository.DefaultArtifactResolver.r

>>>>>>>> esolveInClassLoader(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