flow icon indicating copy to clipboard operation
flow copied to clipboard

Slower startup for Flow 24.4 applications

Open mshabarov opened this issue 1 year ago • 2 comments

Describe your motivation

Vaadin Flow 24.4 applications take ~25% more time for startup compared to 24.3. Ee.g. 7.2 secs vs 9.2 secs.

This is most likely because Vaadin now includes Hilla dependencies and plugins.

As a workaround, one can exclude maven dependencies hilla and hilla-dev to get back to original numbers in 24.3.

This ticket is an investigation issue of a root cause of startup time raise.

mshabarov avatar Feb 27 '24 14:02 mshabarov

I wonder what kind of 24.3 app you use as a refererence? In my tests the difference was pretty much that 2 secs, but 24.3 was somethign like 2 s and 24.4 4 s, making the difference quite a lot more dramatic.

mstahv avatar Feb 28 '24 09:02 mstahv

Well, probably it's always 2 secs that constantly added by Hilla dependencies.

mshabarov avatar Feb 28 '24 10:02 mshabarov

Just based on the Flow's reload time tests, which all run without Hilla, proves that Flow reload times are a bit worse when compared to 24.3. About half of the snapshot test runs fails due to reload time going over the threshold. But difference is below ~100ms, so nothing major directly in Flow.

As pointed out also in the description, Hilla dependencies are now included by default with Vaadin. Workaround is to exclude hilla and hilla-dev dependencies to get reload times at least very close to what it was with 24.3.

Testing with flow-hilla-hybrid-example locally: reload time is ~5s. After removing Hilla dependencies and endpoints and Spring security: reload time drops to ~3s.

tltv avatar Apr 02 '24 14:04 tltv

Testing more with flow-hilla-hybrid-example locally. With 24.3, after removing Hilla dependencies and endpoints and Spring security: reload time drops to ~2s.

Start times in dev mode with flow-hilla-hybrid-example locally, no dev bundle building included: 24.4, plain Flow: ~6.5s 24.4, Flow+Hilla dependencies without client routes: ~9.7s 24.3, plain Flow: ~4s

24.3 took ~1.6s less time in class scanning than 24.4.

Interesting finding is that after excluding also copilot dependency, it reduces reload time to ~2s and start time to ~4s. Which is same as with 24.3. 24.4, plain Flow, no Copilot depenency: ~4s

tltv avatar Apr 03 '24 12:04 tltv

Summarized starting times compared with 24.3 to 24.4: Copilot adds ~2s where 75% of it goes into class scanning. Hilla adds ~3s where 33% of it goes into class scanning. Flow itself adds ~100ms.

tltv avatar Apr 04 '24 07:04 tltv

After excluding com.vaadin.hilla and com.vaadin.copilot packages and including only com.vaadin.copilot.CopilotIndexHtmlLoader, com.vaadin.copilot.CopilotLoader and com.vaadin.hilla.startup from them by default for the class scanning, reload time drops to ~3.2s but startup time drops only little to ~9s.

This could be first easy step to do. It will reduce startup time few percentages. Reload time is reduced 40%.

Flow's package based filtering affects only to what classes are actually checked for Vaadin specific types/annotations. To reduce start time back to what it was with 24.3 would require some way to exclude whole copilot jar from the Spring's classpath based resource scanner. Excluding whole Copilot dependency from the project removes also development tools which is not what developers want to do. Same with Hilla and it can be excluded, but 33% (~1s) goes to class scanning. Rest of time goes to something else.

Both Copilot and Hilla seems to have very limited usage of Flow specific interfaces that are targets of class scanning. However, jars are loaded and scanned fully, which then slows startup.

Tried out to filter whole jar dynamically by extending PathMatchingResourcePatternResolver#doFindPathMatchingJarResources and when excluding all hilla jars, reload time is ~3s and startup time is ~8s. This is one way to speed things up. It gives a way to exclude whole jars from the scanning even when jar is in the classpath:

       @Override
        protected Set<Resource> doFindPathMatchingJarResources(Resource rootDirResource, URL rootDirUrl, String subPattern) throws IOException {
            if(rootDirResource.getURI().toString().contains("com/vaadin/hilla")) {
                return Set.of();
            }
            return super.doFindPathMatchingJarResources(rootDirResource, rootDirUrl, subPattern);
        }

tltv avatar Apr 04 '24 13:04 tltv