I’m trying to understand a behavior on the WorkerExceutor
isolation modes.
So I had workerExecutor.noIsolation()
to validate some stuff with an old version of Apache HttpClient, and this worked well.
Then I wanted to control the JVM, so I switched to workerExecutor.processIsolation
and pass a specific launcher.
However to my surprise, classes from HttpClient 4.5 surfaced.
In a reproducer I noticed that the system class loader was quite different in processIsolation
and actually full of Gradle jars, jackson, ant, groovy, etc. While the noIsolation
has two jars only !
I am misusing / misconfiguring it ?
=======================================================================================
Running MuzzleAction with mode: Submitted to noIsolation queue
~/.gradle/wrapper/dists/gradle-8.14.2-bin/2pb3mgt1p815evrl3weanttgr/gradle-8.14.2/lib/gradle-daemon-main-8.14.2.jar
~/.gradle/wrapper/dists/gradle-8.14.2-bin/2pb3mgt1p815evrl3weanttgr/gradle-8.14.2/lib/agents/gradle-instrumentation-agent-8.14.2.jar
=======================================================================================
Running MuzzleAction with mode: Submitted to processIsolation queue
~/.gradle/caches/8.14.2/workerMain/gradle-worker.jar
~/.gradle/wrapper/dists/gradle-8.14.2-bin/2pb3mgt1p815evrl3weanttgr/gradle-8.14.2/lib/plugins/gradle-daemon-server-worker-8.14.2.jar
~/.gradle/wrapper/dists/gradle-8.14.2-bin/2pb3mgt1p815evrl3weanttgr/gradle-8.14.2/lib/annotations-24.0.1.jar
~/.gradle/wrapper/dists/gradle-8.14.2-bin/2pb3mgt1p815evrl3weanttgr/gradle-8.14.2/lib/ant-antlr-1.10.15.jar
~/.gradle/wrapper/dists/gradle-8.14.2-bin/2pb3mgt1p815evrl3weanttgr/gradle-8.14.2/lib/ant-launcher-1.10.15.jar
... many other (165 in total)
Reproducer code, needs to run the daemon on a JDK 8.
tasks.register<WorkerIsolationReproducerTask>("reproduceWorkerIsolation") {
group = "verification"
description = "Reproduces worker isolation issue with URLClassLoader"
}
open class WorkerIsolationReproducerTask @Inject constructor(
@Internal val workerExecutor: WorkerExecutor,
@Internal val javaToolchainService: JavaToolchainService
) : DefaultTask() {
@TaskAction
fun reproduce() {
workerExecutor.noIsolation().submit(MuzzleAction::class.java) {
mode = "Submitted to noIsolation queue"
}
val selectedLauncher = javaToolchainService.launcherFor {
languageVersion = JavaLanguageVersion.of(8)
}.get()
workerExecutor.processIsolation() {
forkOptions {
executable(selectedLauncher.executablePath)
}
}.submit(MuzzleAction::class.java) {
mode = "Submitted to processIsolation queue"
}
}
}
interface IsolationMode : WorkParameters {
val mode: Property<String>
}
abstract class MuzzleAction : WorkAction<IsolationMode> {
override fun execute() {
println(
"""
|
|=======================================================================================
|Running MuzzleAction with mode: ${parameters.mode.get()}
|
""".trimMargin())
val ucpf = URLClassLoader::class.java.getDeclaredField("ucp")
ucpf.setAccessible(true)
val ucp: URLClassPath = ucpf.get(ClassLoader.getSystemClassLoader()) as URLClassPath
ucp.urLs.forEach { println(it.path) }
}
}
Reproducer worker-isolation.zip (52.6 KB)