Elixir Phoenix не загружает переменную env во время выполнения - PullRequest
1 голос
/ 27 июня 2019

Я пытаюсь загрузить ключ API в качестве системного env с моего Mac при запуске сервера Phoenix. Что я делаю не так? это мои шаги:

  1. На моем терминале Mac:

    export API_NOTIFICATION_KEY=1234
    
  2. в моем config.exs

    config :app, App.Notifications,
    notification_api_key: {:system, "API_NOTIFICATION_KEY"}
    
  3. в моем модуле, где я его использую

    @api_notification_key Application.get_env(:app, App.Notifications)[:notification_api_key]
    
  4. запустить мой сервер Phoenix

    mix phx.server
    

А потом, когда я пытаюсь сделать вызов API, он отображается как ноль. Не хватает ли шага, чтобы загрузить его правильно?

Ответы [ 2 ]

2 голосов
/ 27 июня 2019

Атрибуты оцениваются во время компиляции, поэтому:

@api_notification_key Application.get_env(:app, App.Notifications)[:notification_api_key]

будет иметь значение, установленное во время компиляции.Я предполагаю, что это не то, что вы хотите, поэтому вам будет лучше использовать функцию:

defp api_notification_key() do
  case Application.get_env(:test, App.Notifications)[:notification_api_key] do
    {:system, var_name} -> System.get_env(var_name)
    value -> value
  end
end
0 голосов
/ 28 июня 2019

Когда я использую вашу конфигурацию, попробуйте получить доступ к ключу в контроллере с помощью:

Application.get_env(:app, App.Notifications)[:notification_api_key]

Я получаю:

{:system, "API_NOTIFICATION_KEY"}

, поэтому Феникс не ищет переменную env. С другой стороны, если я вручную установлю ключ в конфиге, вот так:

config :app, App.Notifications,
    notification_api_key: 1234

тогда я получаю 1234 в контроллере. Я прочитал что-то, что говорит, что чтение переменных среды с {:system, "ENV_VAR"} в какой-то момент будет устаревшим, и я не вижу упоминаний о :system в документах. Я использую phoenix 1.4.6.

Согласно этой статье , вы можете определить функцию init/2 в endpoint.ex, которая будет вызываться во время выполнения - непосредственно перед запуском вашего приложения Phoenix - что означает, что вы можете напрямую просматривать Переменные среды во время выполнения с System.get_env/1. Функция init/2 описана в документах Phoenix.Endpoint :

Динамическая конфигурация

Для динамического конфигурирования конечной точки, например загрузки данных из переменные окружения или файлы конфигурации, Phoenix вызывает Обратный вызов init / 2 в конечной точке, передающий атом: supervisor в качестве первого аргумент и конфигурация конечной точки в качестве второго.

Вот пример, который я придумал:

  def init(:supervisor, config) do
    #IO.inspect config, label: "config"
    #IO.inspect Application.get_all_env(:app1), label: "all"

    Application.put_env(:app1, :notification_api_key, 
        System.get_env("API_NOTIFICATION_KEY"),
        persistent: true
    )

    {:ok, config}
  end

Тогда в моем контроллере:

key = Application.get_env(
        :app1, App1.Notifications 
      )[:notification_api_key]

IO.inspect key, label: "key" 

И в окне сервера вижу:

key: 1234

Вы также должны понимать, что установка атрибутов модуля происходит во время компиляции, поэтому эта строка:

@api_notification_key Application.get_env(:app, App.Notifications)[:notification_api_key]

возвращает переменную env для системы, в которой компилируется приложение.

Я также попытался установить атрибут модуля в моем контроллере:

@attr Application.get_env(
        :app1, App1.Notifications 
      )[:notification_api_key]

и init/2 определены в endpoint.ex, как указано выше, и в моем контроллере @attr было равно нулю - как и ожидалось. Это потому, что во время компиляции init/2 еще не был вызван, поэтому значение для :notification_api_key не было установлено.

Мне кажется, что неправильно звонить Application.put_env() в init/2:

  def init(:supervisor, config) do

    Application.put_env(:app1, :notification_api_key, 
        System.get_env("API_NOTIFICATION_KEY"),
        persistent: true
    )

    {:ok, config}
  end

Я думаю, что должен что-то делать с config. Вот еще один пример:

  def init(:supervisor, config) do

    IO.inspect config, label: "config"

    key = System.get_env("API_NOTIFICATION_KEY")
    new_config = Keyword.put_new(config, :notification_api_key, key)

    IO.inspect new_config, label: "inside init/2: new_config"

    {:ok, new_config}
  end

Тогда в моем контроллере:

IO.inspect(
  App1Web.Endpoint.config(:notification_api_key, :not_set), 
  label: "config"
)

В моем окне сервера я вижу:

config: "1234"

так что тоже работает.

...