Using Gradle in a computer cluster causes daemons to lock each other out

We use Gradle in a computer cluster, where we have to submit jobs to available machines. This means that each time we start gradle, it potentially executes on a different machine. All machines have access to the same network file system, so even though the jobs run remotely, they sort of have the same “feel” as running locally.

The Gradle daemon causes issues, though. Running gradle on a machine will leave behind a daemon on that machine. This daemon will lock parts of .gradle (e.g. journal cache). Trying to execute gradle again but landing on a different machine will cause the second invocation to time out, because it can’t acquire locks.

I’ve seen that Gradle daemons running on the same machine will talk to each other, to request access to locked resources. A second invocation which is incompatible with a running daemon can ask this daemon to relinquish its lock so that the second daemon can execute. The communication is based on process IDs. When running in our multi-machine case, daemons can’t talk to each other, because they don’t know how to reach each other. We currently disable daemons altogether, but this is kind of a drain on performance. I’m guessing Gradle, at least the daemon infrastructure, isn’t really built for such a scenario, but I thought I’d ask whether there is anything we could do to be able to work with daemons.

I don’t think it is a good idea to have the GRADLE_USER_HOME on a network drive that is shared / used by multiple machines.
This is most probably the cause of your problems and I don’t think that Gradle supports that or even should support it.
Most software - I know - that have some kind of local cache or similar would not be compatible with multiple machines accessing that cache directory in write-mode.

So to resolve your issue you should most probably make sure, that different machines do not use the same shared GRADLE_USER_HOME.

I thought about this as well. I can’t find an easy way of changing the value of GRADLE_USER_HOME to point to a different location based on the machine it’s running on. I’d like something like GRADLE_USER_HOME=/some/location/for/$(hostname)/.gradle, where $(hostname) returns the name of the machine where gradle was executed on. I don’t know a priori when I submit gradle on which machine it will land, but entries in gradle.properties have to be “simple” values.

That’s not an entry for gradle.properties.
That’s an environment variable.

I’m referring to gradle.user.home, but the environment variable has the same problem.

The way submission works is like the following:

hostA> bsub gradle <task>
<dispatching to hostB>
<... Gradle executes on hostB>

bsub is the command that’s used to submit the job to the cluster.

It’s not possible when executing the bsub gradle command to know on what host it will land on, so it’s not possible to set GRADLE_USER_HOME to any concrete value. Only once the job was submitted is this available.

Well, you should probably not specify it at that level at all, but on the build machine.

If you really need to set it “from the build” dynamically, assuming the build machine uses the wrapper scripts, modify the wrapper scripts to set the environment variable or give the system property with an accordingly calculated value.

There’s only one home directory (i.e. ~) for the user, regardless on which machine they are, so it’s not possible to solve this like that.

So it’s generally ok to modify the Gradle wrapper? Or do you mean another kind of wrapper scripts?

However you like. You can make wrapper scripts calling the wrapper scripts, or you can modify the existing wrapper scripts, if you do it in a way that does not disturb your local execution. And you have to take care to redo it on wrapper updates of course, for example by adding a doLast action to the wrapper task.

I found the following comment in the Gradle wrapper:

This leads me to believe that something like -Dgradle.user.home=.gradle-${HOSTNAME} inside GRADLE_OPTS should lead to Gradle using different user homes for each machine, because the ${HOSTNAME} would get re-expanded.

This doesn’t work, though. Gradle is using literally .gradle-${HOSTNAME} as a user home. Is the comment in the wrapper wrong or am I misinterpreting it? It would also seem strange to have the wrapper do any kind of shell expansion, because that would lead to different results depending on whether ./gradlew or gradle is used to start it.

I guess the comment is either wrong or misleading, as there is extra code to escape meaningful characters so that no eval happens there.

I’ve created an issue for this: Comment in wrapper w.r.t. shell expansion of environment variables is wrong/misleading · Issue #25958 · gradle/gradle · GitHub

1 Like