Questionn Regarding Module attributes

I am trying to set module attribute at the time of compilation. But the fact it should throw errorr its not

  @chaser_after (case Application.compile_env(:kcore, :app_env)do
                   "prod" ->
                     DateTime.utc_now() |> DateTime.add(3, :day)

                   "staging" ->
                     DateTime.utc_now() |> DateTime.add(3, :hour)

                   "dev" ->
                     DateTime.utc_now() |> DateTime.add(3, :hours)

                   _ ->
                     if Mix.env() === :test do
                       nil
                     else
                       DateTime.utc_now() |> DateTime.add(10, :minute)
                     end
                 end)

config :kcore, :app_env, System.fetch_env!(“APP_ENV”) defined in runtime

My current env is dev , it should crash at
DateTime.utc_now() |> DateTime.add(3, :hours)
due to :hours not being :hour .

I dont understand whats happening.

instead this code is being executed
DateTime.utc_now() |> DateTime.add(10, :minute)

To help debug a bit, you could try this:

 @thing DateTime.utc_now() |> DateTime.add(3, :hours)

And you will see that you get the error you expect. That implies that you are not hitting the branch of the case statement that you expect. So I’d do this to being with:

case Application.compile_env(:kcore, :app_env) |> IO.inspect()

to see what that comes out as

1 Like

its returning nil

You’re reading the config before it’s being set it seems.

1 Like

Yes , because it defined in runtime.exs.

I think issue is being defined in runtime.exs. when I put it config.exs, it throws errror

I want to understand Which config file to use and when?

Okay nice, now remember that module attributes are set at compile time, you have said you set the config in rumtime.exs. What happens if you move that into config/dev.exs ?

1 Like

ok issue is resolved, it being defined in runtime.exs. when I put it in config.exs, it throws errror

but I want to understand Which config file to use and when?

I want to understand Which config file to use and when?

Great question. In general what you have here is a bit of an anti-pattern which I’ll explain a bit. But first in general you put the config inside runtime.exs ONLY if you will only know the value at runtime. When might this be the case? Some examples are:

  1. You build your app on a build server, then move the executable to a different server to run it. The server that you run the app on has the env vars and secrets on it. In that case any env var is only going to be available at runtime, so you’d have to set them in runtime.exs.
  2. You want to be able to re-start the app to change config values, rather than have to rebuild a release.

In most other cases you can likely set it at compile time. Now this though is a bit of a smell:

case Application.compile_env(:kcore, :app_env

Instead what you would do is this:

@chaser_after Application.compile_env!(:kcore, :chaser_after)

Then in the different config files you’d set a different value, eg:

config/prod.exs

config(:kcor, chaser_after: DateTime.utc_now() |> DateTime.add(3, :day))

dev.exs

config(:kcor, chaser_after: DateTime.utc_now() |> DateTime.add(3, :hour))

config/staging.exs

config(:kcor, chaser_after: DateTime.utc_now() |> DateTime.add(3, :hour))

etc

2 Likes

so wee use runtime.exs , for putting env values to app , after the build has been built. and we are running that binary on d/f machines , without need of compiling for each d/f machines with d/f config?

or when we want to change the config when the app is already running?

A bit off-topic, but you do know that when you use a module variable it is set at compile time, that means in this case that the DateTime.utc_now() is the value at compile time.
Just wondering.

yea it’s true I didn’t even get to that, it’s hard to tell from the example but it’s more likely you just want to store the :hour, :day offset atom in the config as that’s the thing that changes really