1 2 Previous Next 16 Replies Latest reply on Mar 27, 2008 11:15 AM by alesj

    Handling contexts in error

    alesj

      We should put more info out when users try to manage contexts that are in Error state.
      Since currently the only way to do a re-try on that context is to do uninstall/re-install.
      Users might try this

       KernelControllerContext context = getControllerContext("Name1", null);
       assertEquals(ControllerState.ERROR, context.getState());
       checkThrowable(ClassNotFoundException.class, context.getError());
      
       // a hacky fix, but the point is to get the error away :-)
       AbstractBeanMetaData bmd = (AbstractBeanMetaData)context.getBeanMetaData();
       bmd.setBean(Object.class.getName());
      
       // we suspect the error was resolved, let's try to install
       change(context, ControllerState.INSTALLED);
      
       assertEquals(ControllerState.INSTALLED, context.getState());
      

      which looks legit, but the thing is that the context would not be even touched - the code only tries to push non-error contexts.

      We could enable the push from Error or just add some more info that this is not what the user should do.

        • 1. Re: Handling contexts in error

           

          "alesj" wrote:

          We could enable the push from Error or just add some more info that this is not what the user should do.


          You can't push from error for at least three reasons:

          1) In a manual process, you'll have people doing:
          change(state1); // This errors
          change(state2); // This will error again (pointlessly)

          Even worse, it will do the wrong thing at undeploy

          deploy:
          change(state1); // ok
          change(state2); // error -> undeployed

          undeploy: (reversing the state machine)
          change(state1); // so it has now deployed to state1 during an undeploy????

          2) The above can happen transitively where changing the state of one context will
          try to push other contexts that depend on it and are now satisfied by
          the changed state (again leading to lots of errors)

          3) If you change the metadata like you say, then you are supposed to re-install.

          Like I've being saying on other threads, we should be cloning that metadata
          so your change in the above example would have no effect anyway.

          If the deployment has errored then it has gone. The context is only retained
          for error summary purposes.
          If there was no need for the IncompleteDeploymentException then an
          error would have been defined to uninstall.

          It's also potentially problematic if somebody changes the BeanMetaData
          in a incompatible way midway through the deployment process
          which is another reason why we should avoid "out-of-band" changes,
          we should require a re-install.

          • 2. Re: Handling contexts in error

            So actually Ales is trying to explain a use case that I need MC to handle for me. Suppose we have the POJO:

            public class Bean {
            
            private int count = 0;
            
            public void start() throws InitializationException
            {
             if (count++ == 0)
             throw new InitializationException();
            }
            
            }
            


            Can MC handle a use case where the failure is not trigerred by its initial state (bean meta data if I understand correctly) like in the use case I am posting ?

            How can I handle the following transitions:

            NOT_INSTALLED -> CREATE -> start() -> ERROR -> start() -> INSTALLED

            if the Bean I listed above is reinstantiated every time it will fail whatsoever. If the same instance is used then it will fail only the first time.

            Please try to get an answer understandable by someone that has little knowledge about MC.

            • 3. Re: Handling contexts in error

               

              "julien@jboss.com" wrote:

              Please try to get an answer understandable by someone that has little knowledge about MC.


              This isn't really an MC question, it's a programming patterns question :-)
              The answer is to use a factory/singleton pattern.

              e.g. These two would use the object constructed by MyFactory
              (which can also be an instance class rather than the shown static method).
              <bean name="Bean1">
               <constructor factoryClass="MyFactory" factoryMethod="getInstance"/>
              </bean>
              
              <bean name="Bean2">
               <constructor factoryClass="MyFactory" factoryMethod="getInstance"/>
              </bean>
              


              ALTERNATIVE:

              If you don't like the boiler plate of coding a singleton factory,
              I wrote an aspect that does it for you:
              http://viewvc.jboss.org/cgi-bin/viewvc.cgi/jbossas/projects/aop/trunk/aspects/src/main/org/jboss/aspects/patterns/singleton/Singleton.java?revision=63048&view=markup
              which I guess could also be configured with an annotation (although it doesn't exist currently).

              <bind pointcut="execution(@com.acme.Singleton->new())">
               <advice name="constructorAdvice" aspect="Singleton"/>
              </bind>
              
              @com.acme.Singleton
              public class MyBean {}
              


              I'm sure you can adapt it to your needs if it doesn't do exactly what you want. ;-)

              • 4. Re: Handling contexts in error

                 

                "adrian@jboss.org" wrote:

                <bind pointcut="execution(@com.acme.Singleton->new())">
                 <advice name="constructorAdvice" aspect="Singleton"/>
                </bind>
                
                @com.acme.Singleton
                public class MyBean {}
                



                I think this pointcut language is wrong, since it requires you to annotate the constructor
                rather than the bean?. But I'm sure you can lookup the correct syntax in the aop docs. ;-)

                • 5. Re: Handling contexts in error

                  ok I see.

                  the other use case it does not answer is that, I need to have some Container bean that list all the related failed POJO to show that it is possible to restart them so:

                  public class Container
                  {
                  private Set<Contained> containeds = new HashSet<Contained>();
                  public void addContained(Contained contained} { // trivial }
                  public void removeContained(Contained contained} { // trivial }
                  public Set<Contained> listContainedThatFailed() { // trivial }
                  }
                  


                  public class Contained
                  {
                   private Container container;
                   public void setContainer(Container container) {
                   // Will be removed when it is possible to do install/uninstall on a specified state, ideally would be instantiated (instead of installed), Ales told me he is working on that feature
                   if (container != null)
                   {
                   container.addContained(this);
                   }
                   else
                   {
                   this.container.removeContained(this);
                   }
                   this.container = container;
                  }
                  


                  so admin could browse the "failed" beans and attempt to restart some of them using the admin tool, or in a programmatic way

                   for (Contained contained : container.listContainedThatFailed())
                   {
                   contained.invokeStart();
                   }
                  




                  I think that the whole point is that I need to consider a bean in the 3 following states:

                  stop/installed/failed

                  and trigger trnasitions :-)

                  where invokeStart() delegates to

                   // Here controllerContext is the one of the failed bean
                   controller.change(controllerContext, ControllerState.INSTALLED);
                  




                  • 6. Re: Handling contexts in error

                    I don't really understand what you are trying to do?
                    Guessing...

                    INSTALL - MC wiring

                    The add/removeContained looks like either the install or installCallback stuff.
                    However, if a bean goes to the error state then it will have its uninstall or
                    uninstallCallback invoked. There's no notion of holding onto a broken bean
                    (except for error reporting - see above).

                    CONTROLLER - a bit more control for yourself

                    If you want to control the states manually then consider writing your own
                    facade over the MC controller, e.g. take a look at what the ServiceController
                    (in the jbossas system-jmx project) does to support the legacy JMX api.

                    i.e. http://viewvc.jboss.org/cgi-bin/viewvc.cgi/jbossas/trunk/system-jmx/src/main/org/jboss/system/ServiceController.java?revision=64966&view=markup

                    * stopping and starting mbeans from the mbean's own jmx operations
                    mbeanserver.invoke() -> mbean.stop() -> servicecontroller.stop() -> MC

                    * emulating the old SAR deployer or programmatic use of the ServiceController
                    to manually change the mbean states

                    * maintaining the legacy ServiceContext and listing them by state
                    http://viewvc.jboss.org/cgi-bin/viewvc.cgi/jbossas/trunk/system-jmx/src/main/org/jboss/system/ServiceContext.java?revision=65327&view=markup
                    e.g.

                    List<ServiceContext> listIncompletelyDeployed() {...}

                    etc.

                    For your usecase, it doesn't sound like it needs to be as complicated
                    as the JMX stuff, but the "invokeStart() delegates to" sounds like a facade/wrapper
                    to me?

                    • 7. Re: Handling contexts in error

                       

                      "adrian@jboss.org" wrote:
                      There's no notion of holding onto a broken bean
                      (except for error reporting - see above).


                      Maybe we could add a notion of errorCallback?
                      i.e. if a bean errors during the startup process then we would invoke this callback,
                      something like:

                      public class Container
                      {
                      @Install
                      public void addContained(Contained contained} { // trivial }
                      @Uninstall
                      public void removeContained(Contained contained} { // trivial }
                      @Error
                      public void addError(Contained container) {}
                      @Removed
                      public void removeError(Contained container) {}
                      }
                      


                      The @Removed is because the only time it will go out of the error state
                      is when it is removed altogether from the controller during the redeploy.

                      But this seems a bit hacky to me? It's looking less like a POJO
                      and more like what the class says it is a "Container" ;-)

                      Perhaps a better approach would be for you to register for events
                      on your "contained" contexts, so you would actually receive:

                      Pseudo code
                      // Your api
                      removeContained(contained);
                      // Out-of-band notifications from the MC
                      errorOccurred(contained, throwable);
                      // Out-of-band notication from the MC at redeployed
                      uninstalled(contained);
                      // Re-installed using your api
                      addContained(contained);
                      


                      • 8. Re: Handling contexts in error

                        Here is my use case:

                        I defined an SPI for that allow to integrate portlet applications / portlet container and portlet filter objects (which have a stop/start/failed life cycle and start() throws Exception / stop() callbacks) with kernel system (whether it is MC or something else).

                        I have two facade of objects:

                        1/ managed object which are exposed to admin and allow to know what exists, the state and life cycle trigger (managedStart() / managedStop())

                        base class is

                        public interface ManagedObjet
                        {
                         ManagedObjectStatus getStatus();
                         void managedStart() throws Exception;
                         void managedStop();
                        }
                        


                        then for instance I have

                        public interface ManagedPortletApplication extends ManagedObject
                        {
                         Collection<ManagedPortletContainer> getPortletContainers();
                        }
                        


                        public interface ManagedPortletContainer extends ManagedObject
                        {
                         ManagedPortletApplication getPortletApplication();
                        }
                        


                        -----------------------------------

                        Then I have the internal API that is aimed at providing wiring capabilities and real start/stop activities

                        public interface PortletContainerService
                        {
                         void setPortletApplication(PortletApplicationService pa);
                         void start() throws Exception;
                         void stop();
                        }
                        


                        public interface PortletApplicationService
                        {
                         void addPortletContainer(PortletContainerService pc);
                         void removePortletContainer(PortletContainerService pc);
                         void start() throws Exception;
                         void stop();
                        }
                        


                        -----------------------------------

                        Now I am trying to get an MC implementation of the Managed* stuff that uses JBoss MC to:

                        1/ manage the *Service objects (wiring and callbacks)
                        2/ provide a managed interface to know about what exists and managed their life cycle
                        3/ be integrated with other MC beans that may exist in the same Kernel (so it is possible to create dependencies between a portlet container and another service, etc...)



                        • 9. Re: Handling contexts in error

                          The MC can do all this, except the failure part.

                          The reason it can't do the failure part is because it follows what is an accepted
                          generally good programming practice (e.g. ejbs do the same)
                          that if the container invokes a bean and it throws an error then you discard
                          that bean. You can't know that the bean is still in a good state because
                          you don't know why it threw the error.

                          PROPOSAL

                          I've had a seperate thought which is probably more acceptable to both
                          you and to me, ;-)

                          What you really want to do is manage the state of the failed beans.
                          i.e. you want to takeover the management of the context in error from the MC
                          and fix it manually.

                          So my solution would be to allow something like:

                          xml pseudo code as always ;-)

                          <bean ... error-handling="manual"/>
                          


                          If for example the bean threw an error in start() then we no longer just discard
                          this bean. Instead we would effectively change its controller mode to "manual"
                          (if it isn't already) and just then revert it to the previous state. i.e. Created in this case
                          or back to Instantiated if the property configuration failed.

                          You can then pick up the management of the bean from there.
                          When you decide to move the bean, we would just clear the error in the
                          controller context and try again (reverting back to automatic if the bean
                          was previously in that mode).

                          We would never try to move a context in such a state without an
                          explicit request on the controller to do so.

                          I don't think this would require a major change in the Controller,
                          most of the work would be in the IncompleteDeploymentException
                          where we would now have to check all contexts at all states
                          to see whether it has an error set (previously we just retrieved those
                          in the **ERROR** state).

                          We may want to only allow this for checked exceptions. i.e. if start throws
                          a RuntimeException or Error, we would still discard the bean
                          or perhaps make it configurable?

                          This semantic would deal with my objections above and give you the
                          ability to manage the failing beans/contexts without having to re-install them.

                          • 10. Re: Handling contexts in error

                            Actually the way I am using it is rather dynamic and it creates metadata at runtime using the Kernel metadata stuff and does not use XML or Annotations.

                            I guess that what I have can be considered as a "deployer" (i.e take meta data and create a set of runtime kernel managed objects).

                            • 11. Re: Handling contexts in error

                               

                              The reason it can't do the failure part is because it follows what is an accepted
                              generally good programming practice (e.g. ejbs do the same)
                              that if the container invokes a bean and it throws an error then you discard
                              that bean. You can't know that the bean is still in a good state because
                              you don't know why it threw the error.


                              this is the programming model that is designed as such.

                              If you take Servlet or Portlet (modelled after Servlet) it is not the same and it is more like a service programming model.

                              • 12. Re: Handling contexts in error

                                 

                                "julien@jboss.com" wrote:
                                Actually the way I am using it is rather dynamic and it creates metadata at runtime using the Kernel metadata stuff and does not use XML or Annotations.


                                That's fine. There would just be a BeanMetaData::getErrorHandlingMode()
                                which would get copied into a ControllerContext::setErrorHandlingMode(ErrorHandlingMode)

                                public enum ErrorHandlingMode
                                {
                                 DISCARD, // The default as now
                                 MANUAL, // What you want
                                 MANUAL_CHECKED, // As manual but RuntimeExceptions, Errors lead to a DISCARD
                                }
                                


                                That's why I called it "pseudo xml" :-)

                                • 13. Re: Handling contexts in error

                                  Ok,

                                  for now I am formalizing the API/SPI I talked about, did an implementation that I can use meanwhile (that would be reused in JBoss Portal + JBoss AS 4.2 anyway) and most importantly writing test cases to assert the correct behavior of the implementation.

                                  once it is done, I will probably collaborate with Ales to get an MC implementation that pass the same unit tests.

                                  It will take me a couple of days before it is done and the MC implementation is a longer term effort but it would be of course nice to get it implemented in the same MC used by AS 5.

                                  • 14. Re: Handling contexts in error
                                    alesj

                                     

                                    "adrian@jboss.org" wrote:

                                    PROPOSAL

                                    I've had a seperate thought which is probably more acceptable to both
                                    you and to me, ;-)

                                    What you really want to do is manage the state of the failed beans.
                                    i.e. you want to takeover the management of the context in error from the MC
                                    and fix it manually.

                                    So my solution would be to allow something like:

                                    xml pseudo code as always ;-)
                                    <bean ... error-handling="manual"/>
                                    


                                    If for example the bean threw an error in start() then we no longer just discard
                                    this bean. Instead we would effectively change its controller mode to "manual"
                                    (if it isn't already) and just then revert it to the previous state. i.e. Created in this case
                                    or back to Instantiated if the property configuration failed.

                                    You can then pick up the management of the bean from there.
                                    When you decide to move the bean, we would just clear the error in the
                                    controller context and try again (reverting back to automatic if the bean
                                    was previously in that mode).

                                    We would never try to move a context in such a state without an
                                    explicit request on the controller to do so.

                                    I don't think this would require a major change in the Controller,
                                    most of the work would be in the IncompleteDeploymentException
                                    where we would now have to check all contexts at all states
                                    to see whether it has an error set (previously we just retrieved those
                                    in the **ERROR** state).

                                    We may want to only allow this for checked exceptions. i.e. if start throws
                                    a RuntimeException or Error, we would still discard the bean
                                    or perhaps make it configurable?

                                    This semantic would deal with my objections above and give you the
                                    ability to manage the failing beans/contexts without having to re-install them.

                                    Are there any other hooks (api changes), apart ErrorHandlingMode enum, you've had in mind?
                                    Picking up bean in the Controller can be done with Controller::change.

                                    1 2 Previous Next