Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configuation Cache breaks class reloading in IntelliJ #29087

Open
gesellix opened this issue May 9, 2024 · 2 comments
Open

Configuation Cache breaks class reloading in IntelliJ #29087

gesellix opened this issue May 9, 2024 · 2 comments
Labels
a:bug in:build-services Shared Build Services in:configuration-cache Configuration Caching

Comments

@gesellix
Copy link

gesellix commented May 9, 2024

Current Behavior

With the configuration cache enabled, reloading classes while debugging a Java app in Jetbrains IntelliJ fails with errors like:

"Can only transition State of build ':project-name' to state BuildFinishHooks from states [Configure, TaskSchedule, ReadyToRun] however it is currently in state ReadyToReset"

Expected Behavior

Class reloading in IntelliJ should work independently of an enabled or disabled configuraton cache.

Context (optional)

I would like to raise awareness of this issue, but I'm not entirely sure if this is an IntelliJ or a Gradle issue. That's why I originally filed an issue at Jetbrains: https://youtrack.jetbrains.com/issue/IDEA-353229/Compile-and-Reload-fails-with-Gradle

Steps to Reproduce

A minimal sample project can be found at https://github.com/gesellix/IDEA-353229 with a demo video included in that repository at https://github.com/gesellix/IDEA-353229/blob/main/IDEA-353229.mp4

Gradle version

8.7

Build scan URL (optional)

No response

Your Environment (optional)

No response

@ljacomet ljacomet added in:configuration-cache Configuration Caching 👋 team-triage Issues that need to be triaged by a specific team and removed to-triage labels May 15, 2024
@ljacomet
Copy link
Member

This issue needs a decision from the team responsible for that area. They have been informed. Response time may vary.


Hey, @gradle/bt-configuration team,

This issue points at some strange things inside Gradle. Can you look and see if you can pinpoint the problem on IJ or Gradle?

@mlopatkin mlopatkin self-assigned this May 21, 2024
@mlopatkin
Copy link
Member

mlopatkin commented May 22, 2024

The issue is in the backlog of the relevant team and is prioritized by them.


So the trigger is the Idea-injected build service, that's why we only see the failure when running "Compile and reload". However, Gradle is doing weird things:

  1. As part of the CC run, Gradle attempts to reset the build state for :buildSrc (resetModels).
  2. It fails because Idea's build service is closed after the internal services are closed, and it refers to some
  3. Gradle attempts to run build finish callbacks, but fails because :buildSrc build is not in the expected state after reset failure
  4. This failure propagates upwards, but is never reported on the console. Idea seems to get it from the tooling API though.

In the end build successfully stores the CC state, so the next run (which is the CC hit) succeeds, because there's no model reset.

This is the stack trace of the first failure.
org.gradle.api.services.internal.ServiceLifecycleException: Failed to stop service 'outputPathCollectorService'.
        at org.gradle.api.services.internal.RegisteredBuildServiceProvider.lambda$maybeStop$1(RegisteredBuildServiceProvider.java:170)
        at org.gradle.internal.Try$Success.ifSuccessful(Try.java:190)
        at org.gradle.api.services.internal.RegisteredBuildServiceProvider.maybeStop(RegisteredBuildServiceProvider.java:165)
        at org.gradle.api.services.internal.DefaultBuildServicesRegistry.lambda$discardAll$8(DefaultBuildServicesRegistry.java:294)
        at org.gradle.internal.build.ExecutionResult.forEach(ExecutionResult.java:128)
        at org.gradle.api.services.internal.DefaultBuildServicesRegistry.lambda$discardAll$9(DefaultBuildServicesRegistry.java:290)
        at org.gradle.api.services.internal.DefaultBuildServicesRegistry.withRegistrations(DefaultBuildServicesRegistry.java:102)
        at org.gradle.api.services.internal.DefaultBuildServicesRegistry.discardAll(DefaultBuildServicesRegistry.java:287)
        at org.gradle.api.services.internal.DefaultBuildServicesRegistry.discardAll(DefaultBuildServicesRegistry.java:283)
        at org.gradle.internal.build.DefaultBuildLifecycleController.lambda$resetModel$2(DefaultBuildLifecycleController.java:141)
        at org.gradle.internal.model.StateTransitionController.lambda$restart$4(StateTransitionController.java:149)
        at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:34)
        at org.gradle.internal.model.StateTransitionController.restart(StateTransitionController.java:146)
        at org.gradle.internal.build.DefaultBuildLifecycleController.resetModel(DefaultBuildLifecycleController.java:138)
        at org.gradle.internal.build.AbstractBuildState.resetModel(AbstractBuildState.java:78)
        at org.gradle.configurationcache.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$2.accept(ConfigurationCacheAwareBuildTreeWorkController.kt:66)
        at org.gradle.configurationcache.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$2.accept(ConfigurationCacheAwareBuildTreeWorkController.kt:64)
        at org.gradle.composite.internal.DefaultIncludedBuildRegistry.visitBuilds(DefaultIncludedBuildRegistry.java:205)
        at org.gradle.configurationcache.ConfigurationCacheAwareBuildTreeWorkController.scheduleAndRunRequestedTasks(ConfigurationCacheAwareBuildTreeWorkController.kt:64)
        at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$scheduleAndRunTasks$1(DefaultBuildTreeLifecycleController.java:77)
        at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$runBuild$4(DefaultBuildTreeLifecycleController.java:120)
        at org.gradle.internal.model.StateTransitionController.lambda$transition$6(StateTransitionController.java:169)
        at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:266)
        at org.gradle.internal.model.StateTransitionController.lambda$transition$7(StateTransitionController.java:169)
        at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:44)
        at org.gradle.internal.model.StateTransitionController.transition(StateTransitionController.java:169)
        at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.runBuild(DefaultBuildTreeLifecycleController.java:117)
        at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.scheduleAndRunTasks(DefaultBuildTreeLifecycleController.java:77)
        at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.scheduleAndRunTasks(DefaultBuildTreeLifecycleController.java:72)
        at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:31)
        at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
        at org.gradle.internal.buildtree.ProblemReportingBuildActionRunner.run(ProblemReportingBuildActionRunner.java:49)
        at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:65)
        at org.gradle.tooling.internal.provider.FileSystemWatchingBuildActionRunner.run(FileSystemWatchingBuildActionRunner.java:140)
        at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:41)
        at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.lambda$execute$0(RootBuildLifecycleBuildActionExecutor.java:40)
        at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:123)
        at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.execute(RootBuildLifecycleBuildActionExecutor.java:40)
        at org.gradle.internal.buildtree.InitDeprecationLoggingActionExecutor.execute(InitDeprecationLoggingActionExecutor.java:66)
        at org.gradle.internal.buildtree.InitProblems.execute(InitProblems.java:36)
        at org.gradle.internal.buildtree.DefaultBuildTreeContext.execute(DefaultBuildTreeContext.java:40)
        at org.gradle.launcher.exec.BuildTreeLifecycleBuildActionExecutor.lambda$execute$0(BuildTreeLifecycleBuildActionExecutor.java:71)
        at org.gradle.internal.buildtree.BuildTreeState.run(BuildTreeState.java:60)
        at org.gradle.launcher.exec.BuildTreeLifecycleBuildActionExecutor.execute(BuildTreeLifecycleBuildActionExecutor.java:71)
        at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor$3.call(RunAsBuildOperationBuildActionExecutor.java:61)
        at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor$3.call(RunAsBuildOperationBuildActionExecutor.java:57)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
        at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor.execute(RunAsBuildOperationBuildActionExecutor.java:57)
        at org.gradle.launcher.exec.RunAsWorkerThreadBuildActionExecutor.lambda$execute$0(RunAsWorkerThreadBuildActionExecutor.java:36)
        at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:267)
        at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:131)
        at org.gradle.launcher.exec.RunAsWorkerThreadBuildActionExecutor.execute(RunAsWorkerThreadBuildActionExecutor.java:36)
        at org.gradle.tooling.internal.provider.continuous.ContinuousBuildActionExecutor.execute(ContinuousBuildActionExecutor.java:110)
        at org.gradle.tooling.internal.provider.SubscribableBuildActionExecutor.execute(SubscribableBuildActionExecutor.java:64)
        at org.gradle.internal.session.DefaultBuildSessionContext.execute(DefaultBuildSessionContext.java:46)
        at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter$ActionImpl.apply(BuildSessionLifecycleBuildActionExecuter.java:92)
        at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter$ActionImpl.apply(BuildSessionLifecycleBuildActionExecuter.java:80)
        at org.gradle.internal.session.BuildSessionState.run(BuildSessionState.java:71)
        at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter.execute(BuildSessionLifecycleBuildActionExecuter.java:62)
        at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter.execute(BuildSessionLifecycleBuildActionExecuter.java:41)
        at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:64)
        at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:32)
        at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:51)
        at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:39)
        at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:47)
        at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:31)
        at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:65)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:39)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:29)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:35)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput.lambda$execute$0(ForwardClientInput.java:39)
        at org.gradle.launcher.daemon.server.clientinput.ClientInputForwarder.forwardInput(ClientInputForwarder.java:88)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:36)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:64)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:63)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:84)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:52)
        at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
        at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:48)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.IllegalStateException: Project services has been closed.
        at org.gradle.internal.service.DefaultServiceRegistry.serviceRequested(DefaultServiceRegistry.java:296)
        at org.gradle.internal.service.DefaultServiceRegistry.getService(DefaultServiceRegistry.java:336)
        at org.gradle.internal.service.DefaultServiceRegistry.find(DefaultServiceRegistry.java:330)
        at org.gradle.internal.service.DefaultServiceRegistry.get(DefaultServiceRegistry.java:315)
        at org.gradle.internal.service.DefaultServiceRegistry.get(DefaultServiceRegistry.java:310)
        at org.gradle.api.internal.AbstractTask.assertDynamicObject(AbstractTask.java:210)
        at org.gradle.api.internal.AbstractTask.getAsDynamicObject(AbstractTask.java:611)
        at org.gradle.kotlin.dsl.provider.plugins.precompiled.tasks.CompilePrecompiledScriptPluginPlugins_Decorated.getProperty(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.PogoGetPropertySite.getProperty(PogoGetPropertySite.java:49)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:329)
        at OutputPathCollectorService$_close_closure1.doCall$original(/Users/mlopatkin/Projects/gradle/triage/29087-compile-and-reload/init.gradle:31)
        at OutputPathCollectorService$_close_closure1.doCall(/Users/mlopatkin/Projects/gradle/triage/29087-compile-and-reload/init.gradle)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:107)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:274)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1030)
        at groovy.lang.Closure.call(Closure.java:427)
        at groovy.lang.Closure.call(Closure.java:416)
        at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2364)
        at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2349)
        at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2402)
        at org.codehaus.groovy.runtime.dgm$204.invoke(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:242)
        at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:51)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:139)
        at OutputPathCollectorService.close(/Users/mlopatkin/Projects/gradle/triage/29087-compile-and-reload/init.gradle:30)
        at org.gradle.api.services.internal.RegisteredBuildServiceProvider.lambda$maybeStop$1(RegisteredBuildServiceProvider.java:168)

So there are several items to be done on the Gradle side:

  1. Make sure build services are actually safe to use in this scenario
  2. Ensure that the failure is properly reported

For the Idea's use case, adding @CompileStatic to OutputPathCollectorService should be enough to work around the issue.

The smallest reproducer is this build.gradle:

import org.gradle.api.services.BuildService
import org.gradle.api.services.BuildServiceParameters

abstract class MyService implements BuildService<BuildServiceParameters.None>, AutoCloseable {
    @Override
    void close() {
        throw new RuntimeException("HaHa")
    }
}

gradle.sharedServices.registerIfAbsent("myServices", MyService) {}.get()

Calling gradle --configuration-cache || echo FAIL shows that build fails without any failure message printed (except for the echo output) unless there's the configuration cache hit.

There is not so much to be done to work around this issue from the build user perspective. One option is to get rid of the build logic being compiled as part of the main build - this includes buildSrc and included plugin builds. These should be replaced with binary dependencies, compiled and deployed separately.

@mlopatkin mlopatkin added in:build-services Shared Build Services and removed 👋 team-triage Issues that need to be triaged by a specific team labels May 23, 2024
@mlopatkin mlopatkin removed their assignment May 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a:bug in:build-services Shared Build Services in:configuration-cache Configuration Caching
Projects
None yet
Development

No branches or pull requests

3 participants