From 2d28a4be34c3769284519001ae34fd6c646acb8e Mon Sep 17 00:00:00 2001 From: agentloop Date: Wed, 10 Jun 2026 12:46:01 +0000 Subject: [PATCH] plan: refresh plan for issue #555 --- ISSUE-555.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 ISSUE-555.md diff --git a/ISSUE-555.md b/ISSUE-555.md new file mode 100644 index 0000000..2898ed1 --- /dev/null +++ b/ISSUE-555.md @@ -0,0 +1,46 @@ +## Background + +PR #554 fixed the Firebase Test Lab build by chaining `./gradlew --stop` after `flutter build apk` so the daemon releases its journal-cache lock before Dagger snapshots the layer. This issue asks whether that daemon is useful in the first place — and if not, suppress it instead of cleaning up after it. + +## Answer to the question + +**The daemon provides zero benefit in this CI path, and there is no "existing daemon" for it to reuse.** + +- Each Dagger `WithExec` runs in its own ephemeral container. When `flutter build apk` returns, the container is torn down and the daemon process is killed. The only thing that survives is on-disk state on the `gradle-cache` volume mount (`/home/ci/.gradle`), including the journal-cache lock file naming the now-dead PID. +- The next exec (`./gradlew --no-daemon app:assembleAndroidTest`) runs in a fresh container with PID 1 = gradlew. There is no live daemon process to connect to, and `--no-daemon` would refuse to anyway — but it still has to *acquire* the journal-cache lock and times out because the stale lock file is still there. +- So the daemon's one job (persist between invocations to amortize JVM startup) cannot happen here: invocation boundaries are container boundaries. The daemon only exists long enough to perform a single build, then is killed — i.e., it behaves like `--no-daemon` but with extra cleanup hazards. + +## Proposed change + +Prevent the daemon from spawning in CI instead of stopping it afterward. This makes `flutter build apk` behave the same way `./gradlew --no-daemon app:assembleAndroidTest` already does, removes the `bash -c "... && ./gradlew --stop"` wrapper, and eliminates the class of stale-lock failures rather than the one observed instance. + +### `ci/main.go` + +1. In `firebaseBase()` (and `androidBase()` for consistency — same cache mount, same risk surface), add an env var that disables the Gradle daemon for every invocation in those containers: + ```go + WithEnvVariable("GRADLE_OPTS", "-Dorg.gradle.daemon=false") + ``` + Scoped to CI containers only, so local `./gradlew` still gets a daemon. + +2. In `BuildAndroidDebugApks()`, revert the first `WithExec` to its pre-#554 form: + ```go + WithExec([]string{"flutter", "build", "apk", "--debug", "--no-pub"}). + ``` + Drop the `bash -c "... && ./gradlew --stop"` wrapper and the comment block explaining the lock-file workaround. + +3. In the second `WithExec`, drop the `--no-daemon` flag since `GRADLE_OPTS` now covers it. Update the adjacent comment (currently explaining stale-daemon-registry reuse) to point at the env-var approach instead, or remove it. + +### Why `GRADLE_OPTS=-Dorg.gradle.daemon=false` and not `gradle.properties` + +`android/gradle.properties` is checked into the repo and read on every developer machine. Setting `org.gradle.daemon=false` there would slow down local Android builds (every `flutter run` would pay full JVM startup). The env var keeps the change inside the CI module. + +## Verification + +- `dagger call test-android-firebase ...` (or whatever invocation #554 was validated against): build APK + androidTest APK succeed end-to-end with no `--stop` step and no journal-lock timeout. +- Confirm the Gradle log from `flutter build apk` shows `Daemon will be stopped at the end of the build` / no "Starting a Gradle Daemon" line, or at minimum that no daemon process is left running before container teardown. +- `assembleAndroidTest` continues to succeed on a warm `gradle-cache` (dependencies still cached on the volume; only the daemon state is disabled). + +## Out of scope + +- Touching `gradle.properties` (developer-facing, daemon still wanted locally). +- Changing the `gradle-cache` mount to non-persistent — defeats the dependency-caching benefit, which is the actual reason the mount exists. -- 2.52.0