skip to content

How does the Gradle client actually locate candidate daemons, and what daemon states matter during discovery?

level: seniorimportance: should knowfreq 22%

answer

  1. per-version registry: address, PID, state, params
  2. IDLE+compatible = candidate; BUSY skipped
  3. stopping/stopped/canceled excluded
  4. params in registry => compatibility enforced here
  5. stale entries reconciled on failed connect

basics

~10 s

Running daemons register themselves (address, PID, state, parameters) in a per-version registry file. The client reads it and considers only daemons in an idle, available state that match the request.

solid answer

~50 s

Each running daemon records an entry in a **registry** under `~/.gradle/daemon/<version>/` containing its connection address, **PID**, current **state**, and the **startup parameters** that define its identity. On invocation the client reads this registry and filters candidates by **state** and **compatibility**. The states that matter for discovery: an **IDLE** daemon (no build running) with matching parameters is reusable; a **BUSY** daemon is executing another build and is skipped; daemons that are **stopping/stopped or canceled** are not candidates. The client connects to a chosen idle, compatible daemon; if it finds none, it spawns one and adds its entry. Because the registry tracks per-daemon parameters, this is also how Gradle decides compatibility — it doesn't just match 'any free JVM', it matches one whose recorded JDK and JVM args satisfy the request. Stale entries (e.g. a daemon that died) are reconciled by the client.

code

bash · 4 lines
bash
# Inspect the registry layout and per-daemon logs
ls -la ~/.gradle/daemon/
ls -la ~/.gradle/daemon/8.7/    # registry.bin + <pid>.log files
# Each daemon's log records its startup JVM and args (its identity)

go deeper

for a junior

Know daemons register themselves and only idle, matching ones get reused.

for a middle

Describe the registry contents (address, PID, state, params) and the IDLE-vs-BUSY filtering.

for a senior

Explain that compatibility is enforced during the same registry scan and how stale entries are reconciled on failed connect.

for a principal

Reason about registry-based discovery as a decentralized coordination mechanism and its implications for CI agents sharing a Gradle user home.

## The registry: how discovery is even possible A daemon is a separate JVM; the client needs a way to find it. Gradle solves this with a **daemon registry** — a small persistent file kept **per Gradle version**, e.g. `~/.gradle/daemon/8.7/registry.bin`. Whenever a daemon starts, it writes an entry; as its situation changes it updates that entry. Each entry holds: - the **address/token** the client uses to connect, - the daemon's **PID**, - its current **state**, - the **identity parameters** (resolved JDK / Java home, JVM args) it was launched with. ## States that matter during discovery The client cares about the daemon's lifecycle state: - **IDLE** — finished its last build and waiting; a candidate for reuse *if* parameters match. - **BUSY** — currently running a build; cannot accept another, so it's skipped. - **STOPPING / STOPPED / CANCELED** — shutting down or gone; not candidates. Discovery therefore = read registry -> keep entries that are IDLE and compatible -> pick one and connect; if the list is empty, fork a new daemon and register it. ## Compatibility is part of selection Because the registry stores each daemon's parameters, the same scan that finds idle daemons also enforces compatibility. The client never connects to an idle daemon whose recorded JDK or JVM args don't satisfy the request — it would rather spawn a fresh one. This is why a free-but-wrong-JVM daemon doesn't get reused. ```bash ls ~/.gradle/daemon/ # one directory per Gradle version ls ~/.gradle/daemon/8.7/ # registry plus per-daemon log files ``` ## Reconciliation of stale entries Daemons can die unexpectedly (killed, OOM). The registry may then hold an entry for a daemon that no longer answers. When the client tries such an address and gets no response, it treats the daemon as gone and removes/ignores the stale entry, falling back to another candidate or to spawning. This keeps discovery robust without a central coordinator. ## Why this is worth knowing Understanding the registry explains *why* discovery is per-version, why a busy daemon never doubles up, and why incompatible idle daemons are skipped — all of which surface as 'why did Gradle start another daemon?' in real life.

  • Why is the daemon registry kept per Gradle version?
    Daemons for different versions are not interchangeable, so each version has its own registry and discovery only considers same-version daemons.
  • What happens if the registry lists a daemon that has since been killed?
    When the client tries to connect and gets no response, it treats the entry as stale, ignores/removes it, and falls back to another candidate or spawns a new daemon.
  • Can the client reuse a BUSY daemon if the parameters match?
    No — a busy daemon is already running a build and cannot accept another, regardless of parameter compatibility.

saying these in an interview costs you the question

  • Saying Gradle scans the OS process table to find daemons instead of using its registry.
  • Claiming an idle daemon is always reused regardless of recorded parameters.
  • Assuming the registry is shared across Gradle versions.

context