In my config/runtime.exs
I have the following:
timezone = System.get_env("TZ") || "Etc/UTC"
unless Timex.is_valid_timezone?(timezone) do
raise """
The timezone specified in the TZ environment variable is invalid.
"""
end
config :my_app, MyApp, timezone: timezone
My intention is that a valid Timezone will work as expected while an invalid one (such as Europe/Börlin
) crashes the application early.In the rest of the App, I can then assume that the user-supplied timezone is always valid.
This works as expected in dev
, on prod
however, this results in a crash at runtime:
ERROR! Config provider Config.Reader failed with:
** (ArgumentError) errors were found at the given arguments:
* 1st argument: the table identifier does not refer to an existing ETS table
(stdlib 6.2) :ets.lookup(:tzdata_current_release, :release_version)
(tzdata 1.1.3) lib/tzdata/release_reader.ex:74: Tzdata.ReleaseReader.current_release
(tzdata 1.1.3) lib/tzdata/release_reader.ex:17: Tzdata.ReleaseReader.simple_lookup/1
(tzdata 1.1.3) lib/tzdata/release_reader.ex:9: Tzdata.ReleaseReader.zone_and_link_li
(tzdata 1.1.3) lib/tzdata.ex:61: Tzdata.zone_exists?/1
(timex 3.7.13) lib/timezone/timezone.ex:230: Timex.Timezone.name_of/1
(timex 3.7.13) lib/timex.ex:857: Timex.is_valid_timezone?/1
/app/releases/0.1.0/runtime.exs:13: (file)
I’m assuming this happens because the Timex
application isn’t started yet when the runtime configuration is evaluated.
So instead, I now have this workaround that achieves the same thing:
defmodule MyApp.Application do
use Application
@impl true
def start(_type, _args) do
with :ok <- validate_timezone_config() do
# shortened
Supervisor.start_link(children, opts)
end
end
defp validate_timezone_config do
timezone = Briefly.user_timezone()
case Timex.is_valid_timezone?(timezone) do
true -> :ok
false -> {:error, "Configured timezone '#{timezone}' is invalid"}
end
end
end
If an invalid timezone is supplied, the app crashes early:
11:39:02.487 [notice] Application briefly exited: Briefly.Application.start(:normal, []) returned an error: "Configured timezone 'Europe/Börlin' is invalid"
** (exit) :terminating
(kernel 10.2.1) application_controller.erl:511: :application_controller.call/2
(kernel 10.2.1) application.erl:367: :application."-ensure_all_started/3-lc$^0/1-0-"/1
(kernel 10.2.1) application.erl:367: :application.ensure_all_started/3
(mix 1.18.2) lib/mix/tasks/app.start.ex:72: Mix.Tasks.App.Start.start/3
(mix 1.18.2) lib/mix/task.ex:495: anonymous fn/3 in Mix.Task.run_task/5
(mix 1.18.2) lib/mix/tasks/run.ex:129: Mix.Tasks.Run.run/5
(mix 1.18.2) lib/mix/tasks/run.ex:85: Mix.Tasks.Run.run/1
(mix 1.18.2) lib/mix/task.ex:495: anonymous fn/3 in Mix.Task.run_task/5
Is this considered an anti-pattern? Is there a more appropriate/easier way to validate runtime configuration during startup?