elixir bug where env variables are not updated
2024 Mar 07
See all posts
elixir bug where env variables are not updated
I have the following snippet of code which configures an
EthereumClient
.
defmodule Network.EthereumMainnet do
use RPC.EthereumClient,
otp_app: :refiner,
client_opts: Application.get_env(:refiner, :rpc_url),
chain_id: Application.get_env(:refiner, :chain_id),
description: "Ethereum Foundation Mainnet",
currency: [name: "Ether", ticker_symbol: "ETH"]
end
## config.exs
config :refiner,
chain_id: Integer.parse(System.get_env("PROOFCHAIN_CHAIN_ID", "1284")) |> elem(0),
rpc_url: System.get_env("NODE_ETHEREUM_MAINNET")
I wanted to configure the EthereumMainnet
on different
URL values and make RPC calls.
-> export NODE_ETHEREUM_MAINNET="https://moonbase-alpha.blastapi.io/<somekey>"
-> iex -S mix
Compiling 32 files (.ex)
iex(1)> Refiner.Network.EthereumMainnet.client()
%Refiner.RPC.JSONRPC.HTTPClient{
request_uri: "https://moonbase-alpha.blastapi.io/<somekey>",
ws_request_uri: "https://moonbase-alpha.blastapi.io/ws",
request_headers: [
{"host", "moonbase-alpha.blastapi.io"},
{"user-agent", "covalent/refiner"},
{"content-type", "application/json"}
]
}
Now when I exit the shell, reset the
NODE_ETHEREUM_MAINNET
variable and restart the iex shell, I
expect the application to pick up the new value.
-> export NODE_ETHEREUM_MAINNET="https://ethereumrpc.org/"
-> iex -S mix
iex(1)> Refiner.Network.EthereumMainnet.client()
%Refiner.RPC.JSONRPC.HTTPClient{
request_uri: "https://moonbase-alpha.blastapi.io/<somekey>",
ws_request_uri: "https://moonbase-alpha.blastapi.io/ws",
request_headers: [
{"host", "moonbase-alpha.blastapi.io"},
{"user-agent", "covalent/refiner"},
{"content-type", "application/json"}
]
}
Clearly the new env value is not picked up. I thought there's some
lingering value in .envrc which has the older value, but that was not
the case.
-> grep 'moonbeam.blastapi.io' -r ./
-> #0 matches
Even closing and restarting a new shell didn't work out.
The key issue is how use
is handled by elixir. The
use
keyword is a macro that is used to inject code from
another module (in this case RPC.EthereumClient
) into the
current module. It effectively translates to
AnotherModule.__using__
which is a macro segment in the
AnotherModule
.
This suggests that the configuration of EthereumMainnet
might be locked in at the compile time, and further runtime changes to
the env value is not picked up. Sure enough, there's a
Application.compile_env
which would report is the env value
changed since the module was compiled.
So using:
defmodule Network.EthereumMainnet do
use RPC.EthereumClient,
otp_app: :refiner,
- client_opts: Application.get_env(:refiner, :rpc_url),
- chain_id: Application.get_env(:refiner, :chain_id),
+ client_opts: Application.compile_env(:refiner, :rpc_url),
+ chain_id: Application.compile_env(:refiner, :chain_id),
description: "Ethereum Foundation Mainnet",
currency: [name: "Ether", ticker_symbol: "ETH"]
end
after this, changing the env value triggers warning on the next
restart:
-> export NODE_ETHEREUM_MAINNET="https://newrpc.org/"
-> iex -S mix
** (Mix) the application :refiner has a different value set for key :rpc_url 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: "https://ethereumrpc.org/"
* Runtime value was set to: "https://newrpc.org/"
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.clean refiner --build"
* 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
One thing you can do now is to run
mix deps.clean refiner --build
to relock the env variable
values, and then start the iex shell.
-> mix deps.clean refiner --build
* Cleaning refiner
iex(1)> Refiner.Network.EthereumMainnet.client()
%Refiner.RPC.JSONRPC.HTTPClient{
request_uri: "https://newrpc.org/",
ws_request_uri: "https://newrpc.org:444/ws",
request_headers: [
{"host", "newrpc.org"},
{"user-agent", "covalent/refiner"},
{"content-type", "application/json"}
]
}
elixir bug where env variables are not updated
2024 Mar 07 See all postsI have the following snippet of code which configures an
EthereumClient
.I wanted to configure the
EthereumMainnet
on different URL values and make RPC calls.Now when I exit the shell, reset the
NODE_ETHEREUM_MAINNET
variable and restart the iex shell, I expect the application to pick up the new value.Clearly the new env value is not picked up. I thought there's some lingering value in .envrc which has the older value, but that was not the case.
Even closing and restarting a new shell didn't work out.
The key issue is how
use
is handled by elixir. Theuse
keyword is a macro that is used to inject code from another module (in this caseRPC.EthereumClient
) into the current module. It effectively translates toAnotherModule.__using__
which is a macro segment in theAnotherModule
.This suggests that the configuration of
EthereumMainnet
might be locked in at the compile time, and further runtime changes to the env value is not picked up. Sure enough, there's aApplication.compile_env
which would report is the env value changed since the module was compiled.So using:
after this, changing the env value triggers warning on the next restart:
One thing you can do now is to run
mix deps.clean refiner --build
to relock the env variable values, and then start the iex shell.