Application.get_env warnings in Phoenix router with Elixir 1.14

Hi,

I’ve got the following code in my Phoenix app’s router.ex to wire up BoomNotifier:

defmodule PremonitionWeb.Router do
  use PremonitionWeb, :router

  unless Application.compile_env(:premonition, :env) == :test do
    use BoomNotifier,
      custom_data: [assigns: [fields: [:current_user]]],
      notifier: BoomNotifier.MailNotifier.Bamboo,
      options: [
        mailer: Premonition.Mailer,
        from: Application.get_env(:premonition, :emails_from),
        to: Application.get_env(:premonition, :error_emails_to),
        subject:
          "Premonition exception on #{Application.get_env(:premonition, PremonitionWeb.Endpoint)[:url][:host]}"
      ]
  end
  ...
end

The config is set in runtime.exs based on shell environment variables, because the application is installed in a couple of different environments, and this all works, with emails arriving with the correct values from each host.

When I switch to Elixir 1.14-rc.1, the compiler starts generating warnings (“Application.get_env/2 is discouraged in the module body, use Application.compile_env/3 instead”). I think I understand the general reason for this, but in this case they do seem to work the way I expect (ie they pick up the correct values from the environment at startup).

Is there a better way to accomplish this? Is there a way to make the warnings go away?

2 Likes

I guess this warning is due to the fact that options passed to your use BoomNotifier, options are resolved at compile time, never at runtime.

So it might mislead you to think that you can change those values and restart your app, without recompiling it.

Just a guess, I might be wrong :man_shrugging:

I think this is a bug in BoomNotifier - the options passed to use BoomNotifier are evaluated at both compile-time and runtime:

Here walkthrough_notifiers will get the config evaluated at compile-time and check it for validity.

BUT

notify_error will evaluate the configuration at runtime!

A pretty common pattern to avoid this situation is to capture the configuration in a module attribute (@boom_config say) and then reference that in notify_error. This will make all the evaluation happen at compile-time.

I guess this warning is due to the fact that options passed to your use BoomNotifier, options are resolved at compile time, never at runtime.

So it might mislead you to think that you can change those values and restart your app, without recompiling it.

Yeah, I kind of thought that was how it works, but I’m definitely seeing different values on different servers, from the same compiled release.

I guess maybe because use is a macro it could be just storing the AST of the code that’s passed to it, and evaluating it at runtime?

All true, but I want it to evaluate at runtime! I just don’t want the warnings (which are breaking my build because I have it compile with --warnings-as-errors).

I would caution against using this flag when compiling dependencies. You can control warnings in your apps, but you can’t control them in deps. Moreover with dependencies it isn’t always possible to write code that works on multiple Elixir versions without some warnings.

1 Like

I would caution against using this flag when compiling dependencies. You can control warnings in your apps, but you can’t control them in deps. Moreover with dependencies it isn’t always possible to write code that works on multiple Elixir versions without some warnings.

Sorry, I was unclear – the warnings are in my code, not in BoomNotifier. I’m only failing on warnings for compile, not deps.compile.

I’m working through a similar issue. I’m using the normal :put_secure_browser_headers plug, and I have a dynamic value that I need to pass in as an allowed source in the Content Security Policy header. (i.e. - an AWS S3 bucket where the name/url will be different in each environment).

I haven’t tried it yet, but I just found this article. It looks like Replug might do the job.