Why must WorkAction parameters be isolatable/serializable, and how does the requirement change across the three isolation modes?
answer
- submit isolates (snapshots) parameters
- in-JVM modes = deep copy
- processIsolation = serialize across forked JVM
- use Property/managed serializable types
- never pass Project/connections/threads
basics
~20 sGradle snapshots (isolates) work parameters when you submit, so each unit gets an independent copy. For processIsolation the parameters must cross to a forked JVM, so they must be serializable. Use Property/managed types, not arbitrary mutable objects.
solid answer
~50 sWhen you `submit` work, Gradle **isolates the parameters** — it takes an independent snapshot so later mutations to the original don't affect the running unit and so parallel units don't share mutable state. For `noIsolation` and `classLoaderIsolation` the units run in the same JVM, so isolation is an in-memory deep copy. For `processIsolation` the parameters must actually **travel to a forked JVM**, which means they have to be **serializable**. That's why Gradle steers you toward managed properties on `WorkParameters` — `Property<T>`, `ListProperty`, `RegularFileProperty`, `ConfigurableFileCollection` — built from serializable values (String, File, primitives, managed types). Stuffing a live, non-serializable object (a database connection, a thread, a Gradle `Project`) into parameters works by luck under noIsolation and breaks under processIsolation. Designing parameters as serializable managed types makes a task portable across all three modes — you can change isolation later without rewriting the action's contract.
code
kotlin · 10 linesinterface RenderParams : WorkParameters {
val source: RegularFileProperty
val title: Property<String>
}
workerExecutor.processIsolation { forkOptions { maxHeapSize = "512m" } }
.submit(Render::class.java) {
source.set(file("in.md")) // serializable File
title.set("Report") // serializable String
}go deeper
Know parameters should be simple serializable values via Property types.
Explain that processIsolation serializes parameters to a forked JVM, so live/non-serializable objects fail.
Distinguish in-JVM deep-copy isolation from cross-process serialization and design parameters to be mode-agnostic.
Mandate serializable, data-only worker parameter contracts in shared plugins so isolation mode can change without API churn.
## Isolation of parameters, not just of code The Worker API isolates two things. Isolation **modes** govern where the *code* runs. Separately, Gradle always **isolates the parameters** you pass: at submit time it snapshots them so that (a) parallel work units don't accidentally share mutable state, and (b) mutating the source object afterward can't perturb in-flight work. This is conceptually independent of the mode but interacts strongly with it. ## In-JVM modes: deep copy Under `noIsolation` and `classLoaderIsolation`, work runs in the daemon JVM. Parameter isolation is an in-memory **deep copy** of the values into the work unit. Values still need to be the kind Gradle can snapshot, but raw byte-serialization isn't strictly required. ## processIsolation: serialization across a process boundary Under `processIsolation`, the work unit lives in a **different JVM**. The parameters must be **serialized**, shipped to the fork, and deserialized there. Anything not serializable — open sockets/streams, threads, `Project`, `Task`, arbitrary mutable graphs — cannot cross and will fail. This is the most common reason a task that "worked" under noIsolation breaks when someone switches it to processIsolation. ## Design parameters to be mode-agnostic Define `WorkParameters` with **managed properties** holding serializable data: ```kotlin interface RenderParams : WorkParameters { val source: RegularFileProperty val outputDir: DirectoryProperty val title: Property<String> val flags: ListProperty<String> } ``` These map to Strings, Files, and primitives that serialize cleanly. Pass *data*, not *live handles*: instead of a connected client, pass a URL and credentials reference and construct the client inside the action. Done this way, the same action runs unchanged under any isolation mode. ## Practical rules - Never put a `Project`, `Task`, `Logger`, live connection, or thread into parameters. - Prefer managed types; if you must pass a custom class, make it `Serializable` with serializable fields. - If you plan to ever fork, write parameters as if they'll be serialized from day one — it's cheap insurance and keeps the action portable across modes.
- A task using noIsolation passes a live HTTP client in its parameters and works. A teammate switches it to processIsolation and it breaks. Why?noIsolation deep-copies in the same JVM, so a non-serializable client object survives. processIsolation must serialize parameters to a forked JVM; the live client isn't serializable, so it fails. Pass a URL/config and build the client inside the action instead.
- Does parameter isolation happen even with noIsolation?Yes. Gradle snapshots parameters on submit regardless of mode so parallel units don't share mutable state and later source mutations don't leak into running work.
saying these in an interview costs you the question
- Assuming parameter isolation is only about processIsolation — Gradle snapshots parameters in every mode.
- Passing non-serializable live objects (Project, connections) and relying on noIsolation to tolerate them.