How to debug configuration cache of environment variables?

Hi all :wave: I have this curious bug with configuration cache that I do not know how to debug. How can I debug environment variables with HOCON when using gradle run?

It’s a ktor-application that use HOCON (application.conf). HOCON reads environment variables and the application is started with ./gradlew :project:run. Whenever the environment variable changes I need to bust the configuration cache with --no-configuration-cache, or else the application gets the previous value. All team members can reproduce in the same project, with different operating systems (Mac, Linux), but I’m unable to reproduce with a minimal example. Therefor I’m pretty sure this is a configuration issue, not a bug, but I may be mistaken.

The code in question:

fun main(args: Array<String>): Unit = io.ktor.server.cio.EngineMain.main(args)

@Suppress("unused", "LongMethod")
fun Application.module(init: ApplicationSpec.() -> Unit = {}) {
    val someEnv = environment.config.property("some.env").getString()
    val someEnvFromEnvironment = System.getenv("SOME_ENV")

    log.info("SOME_ENV: '$someEnv'")
    log.info("Environment SOME_ENV: '$someEnvFromEnvironment'")
    // more config of the real application below

application.conf:

some.env = ""
some.env = ${?SOME_ENV}

Running (copied the relevant parts):

❯ export SOME_ENV=arve
❯ ./gradlew :person:run
Starting a Gradle Daemon, 2 busy Daemons could not be reused, use --status for details
Configuration on demand is an incubating feature.
Reusing configuration cache.
... logstatements from logback here
08:24:19.062 INFO  Application - SOME_ENV: 'arve'
08:24:19.062 INFO  Application - Environment SOME_ENV: 'arve'

Then updating the environment variable gives same results:

❯ export SOME_ENV=peder
❯ ./gradlew :person:run
Starting a Gradle Daemon, 3 busy Daemons could not be reused, use --status for details
Configuration on demand is an incubating feature.
Reusing configuration cache.
... logstatements from logback here
08:26:21.291 INFO  Application - SOME_ENV: 'arve'
08:26:21.291 INFO  Application - Environment SOME_ENV: 'arve'

Busting the cache gives wanted result:

❯ ./gradlew :person:run --no-configuration-cache
Starting a Gradle Daemon, 4 busy Daemons could not be reused, use --status for details
Configuration on demand is an incubating feature.
... logstatements from logback here
08:27:39.920 INFO  Application - SOME_ENV: 'peder'
08:27:39.921 INFO  Application - Environment SOME_ENV: 'peder'

If one want to see the whole setup, I’ve created a repo based of the gradle- and ktor init guides: GitHub - arve0/gradle-configuration-cache, but as said, this does not reproduce the error.

I’m mostly interested in how I would go to debug caching of environment variables in gradle.

The difference from your minimal example that does not reproduce the problem and your actual real-world case is, that in your real-world case you most probably set any other environment variable on the run task.

With this small change, your minimal example becomes an MCVE:

diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 093988d..598260a 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -17,3 +17,7 @@ application {
     // Define the main class for the application.
     mainClass.set("io.ktor.server.cio.EngineMain")
 }
+
+tasks.run.configure {
+    environment("foo", "bar")
+}

Whether this is known shortcoming or a bug I don’t know.
I suggest now with a complete MCVE you report a bug.
I guess that when setting explicit environment variables all environment variables are stored to CC while they are not when you have no explicitly set ones.
So in your original example it always uses the current inherited env variables, while with my “fix” it uses the ones from CC entry.

I guess this is a bug and only the explicitly set ones should make it into the CC entry.
But I did not find an issue for it, so I think you should create one.

As a work-around, you can for example manually set it like:

diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 093988d..cfcd7e3 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -17,3 +17,8 @@ application {
     // Define the main class for the application.
     mainClass.set("io.ktor.server.cio.EngineMain")
 }
+
+tasks.run.configure {
+    environment("foo", "bar")
+    System.getenv("SOME_ENV")?.let { environment("SOME_ENV", it) }
+}

Actually just doing System.getenv("SOME_ENV") anywhere at configuration time would be enough as it then is a CC input and so makes the CC entry discarded if changed.
The explicit setting just makes it a bit clearer why it is necessary, but can as well be left out.