vaadin/vaadin-gradle-plugin

Build failed - Unable to compute frontend dependencies

mcooper7290 opened this issue ยท 9 comments

Desktop (please complete the following information):

  • OS: Windows
  • JDK version: OpenJDK 8
  • Gradle version: 6.5.1
  • Vaadin Plugin version: 0.8.0 and 0.7.0

Describe the bug
A clear and concise description of what the bug is.
When running "gradle vaadinBuildFrontend" it fails with "Unable to compute frontend dependencies". This occurs if the same command has been previously run and the gradle daemon is still running.

If I kill the gradle daemon and run the same command again it works.

Full stacktrace attached.

gradle-stacktrace.txt

To Reproduce
Steps to reproduce the behavior:

  1. Setup project '...'
  2. Run Gradle task '....''
  3. See error '....'

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Additional context
Add any other context about the problem here.

Hi, thank you for letting us know. Could you please try running Gradle again, but this time with --stacktrace --info switches? That should provide much more insight as to what's going on.

The log.0.txt file contains output from "gradle --stacktrace --info vaadinBuildFrontend" with the failure. After that I ran "gradle --stop" and then the same "gradle --stacktrace --info vaadinBuildFrontend" which succeeds (see log.1.after.stop.t.xt).

log.0.txt
log.1.after.stop.txt

This looks to be the source of the exception:

JAR entry cmb/cabridge/api/entity/SubjectBindingEntity.class not found in C:\Users\mcooper\ws\cmb\6.0\CmbProduct\Common\build\libs\Common-6.0.85.jar

It could be a bug in Vaadin's class discovery code. Could you please verify that the class exists in the jar file?

Could it be that the jar file is not yet produced completely? Could you please try to disable parallel builds via org.gradle.parallel=false?

Yes the SubjectBindingEntity.class file is definitely in the Common-X.X.X.jar file.

I ran again using "--no-parallel" and got a similar failure, though it reported a different file:

Caused by: java.io.FileNotFoundException: JAR entry cmb/model/entity/CertificatePurposeEntity.class not found in C:\Users\mcooper\ws\cmb\6.0\CmbProduct\Model\build\libs\Model-6.0.86.jar

I also confirmed Model-6.0.86.jar contains CertificatePurposeEntity.class

log.2.no-parallel.txt

Thank you so much for taking the time and investigating the issue ๐Ÿ‘

This bug is really interesting, and investigating this issue opens quite a lot of questions - kinda feels like going down a rabbit hole :-D . Comparing the two stack traces:

Caused by: java.io.FileNotFoundException: JAR entry cmb/model/entity/CertificatePurposeEntity.class not found in C:\Users\mcooper\ws\cmb\6.0\CmbProduct\Model\build\libs\Model-6.0.86.jar
	at com.vaadin.flow.server.frontend.scanner.FrontendDependencies.visitClass(FrontendDependencies.java:467)
	at com.vaadin.flow.server.frontend.scanner.FrontendDependencies.visitClass(FrontendDependencies.java:479)

and the older one

Caused by: java.io.FileNotFoundException: JAR entry cmb/cabridge/api/entity/SubjectBindingEntity.class not found in C:\Users\mcooper\ws\cmb\6.0\CmbProduct\Common\build\libs\Common-6.0.85.jar
	at com.vaadin.flow.server.frontend.scanner.FrontendDependencies.visitClass(FrontendDependencies.java:467)
	at com.vaadin.flow.server.frontend.scanner.FrontendDependencies.visitClass(FrontendDependencies.java:479)

we can see that the bug is "caused" by different jar files. That hints to some kind of a threading issue, or alternatively all the files are "somehow broken" at that very point in time, and it's just the matter of iteration order (whichever file is picked first).

I've tried to investigate the stacktrace, but to no avail: the exception is apparently thrown directly by the call to url.openStream() - that's not possible since the exception can only be thrown by a throws clause. This suggests that the JVM is "lying" to us, or somehow collapses the stack-traces. I've found that such an exception can only be thrown at two places on my OpenJDK 1.8: the sun.net.www.protocol.jar.JarURLConnection:142 and sun.net.www.protocol.jar.JarURLConnection:160. The code is pretty horrible and quickly jumps into native code, so it's really hard to see what's going on and whether there actually is a cause exception, masked by the code somewhere.

However, upon investigating, I've discovered that Flow doesn't close the InputStream properly when reading the class file (at FrontendDependencies.visitClass(FrontendDependencies.java:467). Could this be the cause we are looking for? My current theory is that since Flow doesn't close the files properly, they stay open (and locked by the Windows file system) while the Gradle Daemon is running. Running another Gradle build may then start another daemon process, which will try to open the same jar files and fail to do so, since they're opened and locked by the other Daemon process. This would under normal circumstances result in an IOException being thrown; however it's possible that the JVM code swallows the exception somewhere and throws FileNotFoundException instead, much later on ๐Ÿ‘Ž .

This theory is supported by the fact that everything start to work once you kill the Gradle Daemon process. However, opening a file for reading usually doesn't create an exclusive lock on the file, therefore other processes should be able to open the very same jar file for reading as well, which somewhat disproves the hypothesis... Perhaps JarFile accidentally uses exclusive locks?

Could you please try killing the gradle daemon, then building the project repeatedly with --no-daemon flag? If the build succeeds, that would hint that the theory is indeed valid.

Nevertheless, I've created a pull request for Vaadin Flow to correctly close those InputStreams, which could hopefully fix this issue as well ๐Ÿ‘ vaadin/flow#9002

The fix has been merged into Flow and should therefore appear in the next releases of Flow: 4.0.2 for Gradle Plugin master, and 2.3.6 for Gradle Plugin 14.x.

When I used --no-daemon (e.g. "gr --no-daemon --stacktrace --info vaadinBuildFrontend") the builds worked each time I ran them. So this does seem to confirm your theory.

I will wait for the next releases.

Thanks for fixing!

Awesome, thank you for confirming ๐Ÿ‘ We just need to wait for the next Flow release: https://github.com/vaadin/flow/tags

The bug is fixed on master, however we're waiting for flow 2.3.6 release to also fix this on the 14.x branch.