DEV Community

Marco Mannucci
Marco Mannucci

Posted on

Gradle daemon with multi module Spring project

I'd like to share the way I'm handling a multi module project in Spring. In particular, how to start multiple web applications at once taking advantage of the Gradle daemon.

The problem

I've a multi module project which comprises different web apps that should run together.
I noticed that executing

gradle :application_A:bootRun

and, once application_A is built and running,

gradle :application_B:bootRun

two different Gradle daemons are spawn even if the two executions are eligible for using the same daemon.
You can check it with the command:

gradle --status

You should see something similar to

   PID STATUS   INFO
 23606 BUSY     3.5.1
 24703 BUSY     3.5.1

(I know, that's and old version of Gradle...)

This has a huge performance impact, since a gradle daemon is quite eager in term of resources and having different instances defies its very purpose.

Why does that happen?

The reason why the second Spring application is not using the existing daemon is that the bootRun task simply does not terminate: it remains in the running state until we explicitly kill the process. This behavior keeps the daemon in BUSY state so application_B is obliged to spawn a new daemon.

What can we do?

Assuming we don't want to disable the Gradle daemon (that of course will solve the problem...) or simply we can't (e.g. the Tooling API used by IDEs always starts a daemon), the first solution that comes to mind is to execute the two tasks as a single Gradle command, like that:

gradle :application_A:bootRun :application_B:bootRun

Unfortunately, this does not solve our problem... Gradle will gladly run application_A but once again will stop on that task until we don't terminate it. So, this time we have one single daemon, but also one single app started 🙄.

So?

Turns out that the latter is indeed the correct approach but we have to enable parallel execution, which will allow Gradle to run multiple task in parallel, without waiting for the previous task to end. In particular, it will try so execute :application_B:bootRun even if :application_A:bootRun is not terminated (our original problem).

This is as simple as adding the --parallel flag.

gradle :application_A:bootRun :application_B:bootRun --parallel

Now you should see both the apps up and running waiting for requests 😊.

In older versions of Gradle (like mine) this is not sufficient. We should also tell Gradle the number of workers it is allowed to use. Apparently, it otherwise sticks to 1 so that, even with --parallel flag, the execution is sequential.
We can easily solve this with the --max-workers flag:

gradle :application_A:bootRun :application_B:bootRun --parallel --max-workers=4

Top comments (0)