When building IDE integration, when would you launch work with BuildLauncher.forTasks() versus running a BuildAction, and what trade-offs guide the choice?
answer
- BuildLauncher.forTasks -> execute tasks (Void)
- action(BuildAction) -> compute value via BuildController
- action executer can forTasks too (one round-trip)
- BuildAction result must be serializable
- shared: args/output/cancellation/progress
basics
~10 sUse BuildLauncher.forTasks() to execute named tasks (the build). Use connection.action(BuildAction) when you need to run logic inside the build and return a computed value, optionally also executing tasks via forTasks() on the action executer.
solid answer
~50 s`BuildLauncher` is for *executing tasks* — you name them with `forTasks()` and call `run()`; the result is `Void`. A `BuildAction` (run via `connection.action(...)` returning a `BuildActionExecuter`) is for *computing a value* from inside the build: your action runs in the build process with access to the `BuildController`, can query several models efficiently in one connection round-trip, and returns a custom serializable object. For pure task execution, `BuildLauncher` is simpler and the right tool. When you need to gather IDE models (project structure, dependencies) — possibly *and* run tasks in the same invocation — the `BuildActionExecuter` lets you `forTasks(...)` alongside the action, avoiding multiple daemon round-trips. The trade-off is complexity and serialization constraints (the action and its result cross the process boundary, so they must be on the right classpath and serializable). For a Stop button, both honor a shared `CancellationToken`; for live output, both accept `setStandardOutput`. Choose `BuildLauncher` for 'just run these tasks', and a `BuildAction` when you must run custom in-build logic or fetch composite information.
code
kotlin · 8 lines// Plain task execution
connection.newBuild().forTasks("assemble").run()
// Run in-build logic AND tasks in a single round-trip
val model: MyModel = connection.action(MyBuildAction())
.forTasks("generateSources")
.withCancellationToken(source.token())
.run()go deeper
Recall that BuildLauncher.forTasks() runs tasks; deeper action() trade-offs are above this level.
Explain that BuildAction computes a value in the build and can also run tasks, unlike a plain BuildLauncher.
Weigh round-trip economy vs serialization complexity and pick the right operation per IDE use case.
Architect an IDE sync/run layer: minimize daemon round-trips, isolate classpath/serialization risk, and unify cancellation/output across operations.
## Two ways to drive the daemon The Tooling API offers distinct operations for distinct intents: - **BuildLauncher** (`connection.newBuild()`): *execute tasks*. You select tasks with `forTasks(...)`, configure I/O/args, and `run()`. Output: a successful/failed build (`Void`). - **BuildActionExecuter** (`connection.action(BuildAction<T>)`): *run code inside the build and return T*. Your `BuildAction` executes in the build process, receives a `BuildController`, and can call `controller.getModel(...)` for one or many models, then return a custom value. (There are also `ModelBuilder` for a single model and `TestLauncher` for tests — both sibling concerns.) ## Why a BuildAction can also run tasks The `BuildActionExecuter` itself exposes `forTasks(...)` and `forLaunchables(...)`. This lets an IDE, in a *single* connection/invocation, both **execute tasks** and **compute models** — avoiding several separate daemon round-trips. That round-trip economy is the main performance reason to reach for an action instead of issuing a model fetch and a `BuildLauncher.run()` separately. ## Trade-offs | Concern | BuildLauncher.forTasks() | BuildAction via action() | |---|---|---| | Intent | Run named tasks | Compute a value / gather models (optionally + tasks) | | Result | Void | Your serializable T | | Runs your code in build process? | No | Yes (BuildController) | | Complexity / classpath | Low | Higher — action + result must serialize across the process boundary | | Round-trips for models+tasks | Multiple | One | ## Cross-process constraints Because a `BuildAction` and its return value cross from the build daemon back to your client, both must be **serializable** and resolvable on the appropriate classpaths. This is a real source of bugs (ClassNotFound / serialization errors) that `BuildLauncher` simply doesn't have. ## Shared launcher capabilities Both are `LongRunningOperation`s, so the same knobs apply: `withArguments`, `setStandardOutput`/`setStandardError`, `withCancellationToken`, `addProgressListener`, sync `run()`/`run()` vs async `run(ResultHandler)`. ## Decision rule - Just need to run `clean build`? -> **BuildLauncher.forTasks()**. - Need custom in-build logic, or to fetch IDE models (and maybe run tasks too) in one shot? -> **BuildAction via action()**. ``` // execute tasks connection.newBuild().forTasks("assemble").run(); // compute a value (and optionally run tasks) in one round-trip MyModel m = connection.action(new MyBuildAction()) .forTasks("generateSources") .run(); ```
- Why can running tasks via a BuildAction be more efficient than a separate model fetch plus BuildLauncher?The BuildActionExecuter's forTasks() runs tasks and computes models in one connection round-trip to the daemon, avoiding multiple invocations and connection setup costs.
- What new failure mode does a BuildAction introduce versus BuildLauncher?Serialization/classpath issues: the action and its returned value cross the client/daemon process boundary and must be serializable and resolvable on the right classpaths.
- Do BuildLauncher and BuildActionExecuter share configuration like cancellation and output?Yes — both are LongRunningOperations, so withCancellationToken, setStandardOutput/Error, withArguments, progress listeners, and sync/async run all apply.
saying these in an interview costs you the question
- Using a BuildAction merely to run tasks when BuildLauncher.forTasks() suffices.
- Forgetting that a BuildAction's result must be serializable across processes.
- Believing only BuildLauncher (not action()) can execute tasks.