We are using heroku to deploy Phoenix and Elixir based applications. Also we use heroku pipelines to promote from staging to production. I have set for each env the proper MIX_ENV (staging and prod)
I am having an issue regarding accessing config variables for each environment.
When I deploy to staging I have the staging domain.
But when I promote it to production I still have the staging value.
From my current level of understanding since I am loading this variable inside a function and not as a module attribute it is loaded at runtime not at compile time.
Does heroku moves the staging to production without restarting it and loading new environment variables?
I have no idea how to fix this other than not using heroku pipelines.
They said that the profile is created at build time by buildpack. When we use Pipeline promotions there is no build when releasing to production. That means the application is not recompiled. So the only solution to deploy to staging and production and to compile again for each one is not to use pipelines or to set MIX_ENV=production also for staging.
Heroku does not support Elixir by default. I am using a custom buildpack that Heroku does not maintain: https://github.com/HashNuke/heroku-buildpack-elixir
The support guys that I talked to said that this buildpack causes the problem. When promoting the dyno from staging to production it does set MIX_ENV=staging overriding the one from machine.
The application on Heroku is started using mix phoenix.server from Procfile.
Since Elixir is a compiled language and since there are things that are built at this step like module attributes and logger compile_time_purge_level I prefer to deploy them separately and compile the app again.
The issue also seems to instead be that that you are reading from the environment at compile time, these values obviously wont change unless you recompile the application regardless if the buildpack is fixed or not. If you move the Application.get_env from the module attribute into the function that is evaluated at runtime it may work.
imho, and just my 2 cents - your staging env on heroku should be as close to your production env, eg. MIX_ENV should be prod in both of them, and then the ENV variables will be different for DB,S3 etc etc.
You need to change the staging app to use the new buildpack, because we no longer persist the MIX_ENV in the first stage of the pipeline.
Sorry, I have no idea why this is happening. I would suggest starting a dyno with only bash and check if the files are where they are supposed to be. Start with heroku run -a MYAPP bash and check if rebar files are where the buildpack said they put them.
This is definitely what you should do. Mix assumes your app runs in the environment you build, for example you have to set build_per_environment: false in your mix project if you don’t.
I extracted the config variables that are different for each environment to system ENV vars and instead of setting them in module attributes I added methods that loads the variable at runtime like this:
defp api_domain do
Now everything works ok. I can promote servers on pipeline and the new variables are visible. So I can say I am pleased with the result.
I have a question regarding this approach: Getting the variable from system environment for each call does not have a performance penalty instead having the value inside module attribute? I know that it’s insignificant but still I am asking.