Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-22050

All extension classes are loaded at once when any is called

    Details

    • Similar Issues:

      Description

      Mar 05, 2014 12:10:01 PM jenkins.InitReactorRunner$1 onAttained
      INFO: Loaded all jobs
      java.lang.Exception: Stack trace
      	at java.lang.Thread.dumpStack(Thread.java:1364)
      	at MyThing$DescriptorImpl.<clinit>(MyThing.java:...)
      	at java.lang.Class.forName0(Native Method)
      	at java.lang.Class.forName(Class.java:270)
      	at hudson.ExtensionFinder$Sezpoz.scout(ExtensionFinder.java:680)
      	at hudson.ClassicPluginStrategy.findComponents(ClassicPluginStrategy.java:310)
      	at hudson.ExtensionList.load(ExtensionList.java:295)
      	at hudson.ExtensionList.ensureLoaded(ExtensionList.java:248)
      	at hudson.ExtensionList.iterator(ExtensionList.java:138)
      	at hudson.ClassicPluginStrategy.findComponents(ClassicPluginStrategy.java:309)
      	at hudson.ExtensionList.load(ExtensionList.java:295)
      	at hudson.ExtensionList.ensureLoaded(ExtensionList.java:248)
      	at hudson.ExtensionList.get(ExtensionList.java:153)
      	at hudson.PluginManager$PluginUpdateMonitor.getInstance(PluginManager.java:1097)
      	at hudson.maven.PluginImpl.init(PluginImpl.java:54)
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      	at java.lang.reflect.Method.invoke(Method.java:606)
      	at hudson.init.TaskMethodFinder.invoke(TaskMethodFinder.java:105)
      	at hudson.init.TaskMethodFinder$TaskImpl.run(TaskMethodFinder.java:169)
      	at org.jvnet.hudson.reactor.Reactor.runTask(Reactor.java:282)
      	at jenkins.model.Jenkins$7.runTask(Jenkins.java:899)
      	at org.jvnet.hudson.reactor.Reactor$2.run(Reactor.java:210)
      	at org.jvnet.hudson.reactor.Reactor$Node.run(Reactor.java:117)
      	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
      	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
      	at java.lang.Thread.run(Thread.java:744)
      Mar 05, 2014 12:10:05 PM org.jenkinsci.main.modules.sshd.SSHD start
      INFO: Started SSHD at port 58096
      Mar 05, 2014 12:10:05 PM jenkins.InitReactorRunner$1 onAttained
      INFO: Completed initialization
      

      The Maven plugin is trying to load a random AdministrativeMonitor type, and all static initializers are getting called.

        Attachments

          Activity

          Hide
          jglick Jesse Glick added a comment -

          Because ExtensionFinder.SezPoz.scout calls Class.forName(…, true, …).

          Show
          jglick Jesse Glick added a comment - Because ExtensionFinder.SezPoz.scout calls Class.forName(…, true, …) .
          Hide
          jglick Jesse Glick added a comment -

          I think some plugins rely on this unfortunate behavior, making changing it a potential compatibility issue.

          Show
          jglick Jesse Glick added a comment - I think some plugins rely on this unfortunate behavior, making changing it a potential compatibility issue.
          Hide
          kohsuke Kohsuke Kawaguchi added a comment -

          To me, the fact that all extensions are loaded & instantiated is a feature that brings predictability to the boot sequence. Given that Jenkins is a server application, I like that when Jenkins boots up I know all the components are functioning. Imagine the opposite; Jenkins claims it came up OK, but when I run a matrix project, it blows up trying to list Axis extension points, because one of the plugins I have is missing a dependency.

          The problem IMHO is that we have this unnecessary unpredictability today that we don't load extensions until someone tries to look at some extensions for the first time. This is a significant enough event that it should be even explicitly defined as an InitMilestone.

          Also, the bug description lacks what the problem is. The performance tag seems to tell me that Jesse thinks this is a startup performance problem, but I thought loading extensions is usually a tiny part of it. Isn't this more of a diagnosability problem?

          Show
          kohsuke Kohsuke Kawaguchi added a comment - To me, the fact that all extensions are loaded & instantiated is a feature that brings predictability to the boot sequence. Given that Jenkins is a server application, I like that when Jenkins boots up I know all the components are functioning. Imagine the opposite; Jenkins claims it came up OK, but when I run a matrix project, it blows up trying to list Axis extension points, because one of the plugins I have is missing a dependency. The problem IMHO is that we have this unnecessary unpredictability today that we don't load extensions until someone tries to look at some extensions for the first time. This is a significant enough event that it should be even explicitly defined as an InitMilestone . Also, the bug description lacks what the problem is. The performance tag seems to tell me that Jesse thinks this is a startup performance problem, but I thought loading extensions is usually a tiny part of it. Isn't this more of a diagnosability problem?
          Hide
          jglick Jesse Glick added a comment -

          I am concerned here about startup performance, not diagnosability.

          when I run a matrix project, it blows up trying to list Axis extension points

          Well it should not “blow up”, it should simply skip over unloadable extension points with a warning, as currently happens during startup.

          one of the plugins I have is missing a dependency

          That issue is better handled directly by the plugin manager.

          Show
          jglick Jesse Glick added a comment - I am concerned here about startup performance, not diagnosability. when I run a matrix project, it blows up trying to list Axis extension points Well it should not “blow up”, it should simply skip over unloadable extension points with a warning, as currently happens during startup. one of the plugins I have is missing a dependency That issue is better handled directly by the plugin manager.
          Hide
          kohsuke Kohsuke Kawaguchi added a comment -

          But you get the point, right? As an user, I'd rather find problems earlier than later. If one of the extension points do not load, have a problem initializing, or whatever, I'd rather see that error during the boot, not when some code actually attempts to use it.

          Show
          kohsuke Kohsuke Kawaguchi added a comment - But you get the point, right? As an user, I'd rather find problems earlier than later. If one of the extension points do not load, have a problem initializing, or whatever, I'd rather see that error during the boot, not when some code actually attempts to use it.
          Hide
          jglick Jesse Glick added a comment -

          I thought loading extensions is usually a tiny part of it

          My preliminary results suggest something around 40% given a small $JENKINS_HOME.

          Obviously a production instance is going to spend a lot more time loading configuration files, especially jobs. But this is very significant when running tests with JenkinsRule.

          Show
          jglick Jesse Glick added a comment - I thought loading extensions is usually a tiny part of it My preliminary results suggest something around 40% given a small $JENKINS_HOME . Obviously a production instance is going to spend a lot more time loading configuration files, especially jobs. But this is very significant when running tests with JenkinsRule .
          Hide
          jglick Jesse Glick added a comment -

          some plugins rely on this unfortunate behavior

          It may be possible to mechanically detect these cases: if the extension class has a declared constructor or a static initializer, then we must assume that was intended as an implicit @Initializer (though we could issue a warning that it would be better made explicit).

          Of course doing such a check at runtime requires loading, if not fully resolving, the class, which is what we hope to avoid. That is just a small portion of the general problem that when someone asks for the ExtensionList of a particular supertype, we would like to be able to efficiently enumerate all subtypes with @Extension, which is not something we currently have static metadata for (since Jenkins did not use SezPoz as it was designed).

          We could try to build a cache of this information after starting up with all extensions loaded, so that the next startup will be faster. This does not help JenkinsRule, though, and requires the cache to be invalidated based on the set of enabled plugins and their versions.

          We could stop using SezPoz for @Extension and instead define custom processor which records supertypes, and try to get plugins released which are built against this system. Means that any older plugins will still get all their extensions loaded eagerly.

          Show
          jglick Jesse Glick added a comment - some plugins rely on this unfortunate behavior It may be possible to mechanically detect these cases: if the extension class has a declared constructor or a static initializer, then we must assume that was intended as an implicit @Initializer (though we could issue a warning that it would be better made explicit). Of course doing such a check at runtime requires loading, if not fully resolving, the class, which is what we hope to avoid. That is just a small portion of the general problem that when someone asks for the ExtensionList of a particular supertype, we would like to be able to efficiently enumerate all subtypes with @Extension , which is not something we currently have static metadata for (since Jenkins did not use SezPoz as it was designed). We could try to build a cache of this information after starting up with all extensions loaded, so that the next startup will be faster. This does not help JenkinsRule , though, and requires the cache to be invalidated based on the set of enabled plugins and their versions. We could stop using SezPoz for @Extension and instead define custom processor which records supertypes, and try to get plugins released which are built against this system. Means that any older plugins will still get all their extensions loaded eagerly.

            People

            • Assignee:
              Unassigned
              Reporter:
              jglick Jesse Glick
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated: