elixir-cldr / cldr

Elixir implementation of CLDR/ICU
Other
440 stars 33 forks source link

compile configuration mismatch compiletime vs runtime #187

Closed austinh closed 1 year ago

austinh commented 1 year ago

Im getting the following error when compiling a release in prod (does not happen in dev)

5 0.880 ERROR! the application :ex_cldr has a different value set for key :json_library during runtime compared to compile time. Since this application environment entry was marked as compile time, this difference can lead to different behaviour than expected:
#25 0.880
#25 0.880   * Compile time value was not set
#25 0.880   * Runtime value was set to: Poison
#25 0.880
#25 0.880 To fix this error, you might:
#25 0.880
#25 0.880   * Make the runtime value match the compile time one
#25 0.880
#25 0.880   * Recompile your project. If the misconfigured application is a dependency, you may need to run "mix deps.compile ex_cldr --force"
#25 0.880
#25 0.880   * Alternatively, you can disable this check. If you are using releases, you can set :validate_compile_env to false in your release configuration. If you are using Mix to start your system, you can pass the --no-validate-compile-env flag
#25 0.880

my config.exs contains this:

# Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason

config :ex_cldr,
  json_library: Jason

my cldr.exscontains this:

defmodule Ssd.Cldr do
  @moduledoc """
  Define a backend module that will host our
  Cldr configuration and public API.

  Most function calls in Cldr will be calls
  to functions on this module.
  """
  use Cldr,
    locales: ["en"],
    default_locale: "en",
    json_library: Jason,
    providers: [Cldr.Territory]
end

This is running in Docker with this base image

FROM hexpm/elixir:1.13.3-erlang-24.2.2-ubuntu-bionic-20210930
kipcole9 commented 1 year ago

@austinh definitely unexpected behaviour! While I look into why this is happening would you consider removing the json_library config from both the config.exs and the backend configuration?

ex_cldr will (is expected to) derive the json_library automatically from the phoenix configuration if there is one. That will hopefully get you moving forward why I work out what is causing the mismatch.

FWIW, the logic to determine the effective json library is the following compile-time code in lib/config.ex:

  poison = if(Code.ensure_loaded?(Poison), do: Poison, else: nil)
  jason = if(Code.ensure_loaded?(Jason), do: Jason, else: nil)
  phoenix_json = Application.compile_env(:phoenix, :json_library)
  ecto_json = Application.compile_env(:ecto, :json_library)
  cldr_json = Application.compile_env(:ex_cldr, :json_library)
  @json_lib cldr_json || phoenix_json || ecto_json || jason || poison

Is there some chance you have a dependency difference in mix.exs between :dev and :prod? Any chance you could share your mix.exs so I can debug further?

kipcole9 commented 1 year ago

Oh, also you say:

my cldr.exs contains this:

Did you mean cldr.exs? The file should be cldr.ex

austinh commented 1 year ago

Did you mean cldr.exs? The file should be cldr.ex

Sorry yes this file is correctly named cldr.ex - just a typo.

Is there some chance you have a dependency difference in mix.exs between :dev and :prod? Any chance you could share your mix.exs so I can debug further?

I cant share mix.exs because it's a corporate project, and many of the dependencies are hosted on internal hex servers.

However, I can confirm that this happens with compiling just ex_cldr. Running only MIX_ENV=prod mix deps.compile ex_cldr seems to do it. If I then switch to env to dev, recompile again, I still get the error. But if I do a --force, the error goes away (since its now recompiling with dev config). Looks like some kind of build cache issue? The difficulty is on CI when its a fresh environment and it runs in Docker and happens every time no matter what. :( I've even tried the --no-validate-compile-env but no dice, because that solves the mix compile issue, but it happens again on mix release and that has no way to disable that flag from CLI. :(

austinh commented 1 year ago

That will hopefully get you moving forward why I work out what is causing the mismatch.

Ive removed all references to json_library and any ex_cldr config, and still getting the error 😭

kipcole9 commented 1 year ago

Thanks for the update and I'm sorry you're having this issue. Is poison configured in your mix.exs at all? I'm trying to work out how this can even be returned unless its a least configured.

kipcole9 commented 1 year ago

Anything in your config/runtime.exs that relates to ex_cldr? The error message would seem to indicate there may be something there?

austinh commented 1 year ago

Thanks for the update and I'm sorry you're having this issue. Is poison configured in your mix.exs at all?

poison is also configured yes.

Anything in your config/runtime.exs that relates to ex_cldr?

We dont have a config/runtime.exs

austinh commented 1 year ago

Update: I realized we still had Poison set and installed from a previous dependency, it was no longer needed, and I've removed it from deps and did a fresh clean build, still getting the same error, just this time Poison is no longer involved.

Notice how now compile time value is set, but runtime value is not set. This is without any configuration related to json_library set anywhere in any exs file (as per your suggestion)

ERROR! the application :ex_cldr has a different value set for key :json_library during runtime compared to compile time. Since this application environment entry was marked as compile time, this difference can lead to different behaviour than expected:

  * Compile time value was set to: Jason
  * Runtime value was not set

To fix this error, you might:

  * Make the runtime value match the compile time one

  * Recompile your project. If the misconfigured application is a dependency, you may need to run "mix deps.compile ex_cldr --force"

  * Alternatively, you can disable this check. If you are using releases, you can set :validate_compile_env to false in your release configuration. If you are using Mix to start your system, you can pass the --no-validate-compile-env flag

==> ex_cldr
kipcole9 commented 1 year ago

Thanks, that helps a little bit. But I'm surprised to see there is a compile time value set because that directly implies there is a config :ex_cldr, json_library: Jason somewhere being found.

Would you mind MIX_ENV=prod iex -S mix and then seeing what results you get to the following three calls? The ones below come from a new app with only a backend module and only :ex_cldr and :jason configured in mix.exs:

iex(1)> Application.get_env :ex_cldr, :json_library    
nil
iex(2)> Application.compile_env :ex_cldr, :json_library
nil
iex(3)> Cldr.Config.json_library                       
Jason
austinh commented 1 year ago

Unfortunately trying to run that just creates the same error, because mix will try to compile the app and it will fail.

austinh commented 1 year ago

Further interesting finds. When running in MIX_ENV=dev with no ex_cldr config set anywhere. I get this error.

ERROR! the application :ex_cldr has a different value set for key :json_library during runtime compared to compile time. Since this application environment entry was marked as compile time, this difference can lead to different behaviour than expected:

  * Compile time value was set to: Jason
  * Runtime value was not set

When running in MIX_ENV=prod (after clearing all build artifacts), with ex_cldr config set just in config.exs. I get this error.

ERROR! the application :ex_cldr has a different value set for key :json_library during runtime compared to compile time. Since this application environment entry was marked as compile time, this difference can lead to different behaviour than expected:

   * Compile time value was not set
   * Runtime value was set to: Jason

Notice how first one says compile time was set and not runtime. but second one says compile time was not set, but runtime was.

austinh commented 1 year ago

I solved it! Looks like it's an issue with my Dockerfile and why I was having difficulty reproduce locally. If config.exs is not copied over before mix deps.compile - then it will fail. My docker file had mix deps.compile directly before a COPY config ./config - but ive fixed this. Thanks for helping me look into it.

kipcole9 commented 1 year ago

Ahhhh, the will most certainly do it! The config is needed at compile time in order to be able to parse the locale JSON files. Thanks for getting to the bottom of this and for the feedback. If this happens again it will be quicker to resolve the problem for sure!