bitwalker / distillery

Simplify deployments in Elixir with OTP releases!
MIT License
2.97k stars 398 forks source link

**config_providers** and **overlays** options don't work sometimes after mix edeliver restart command #593

Closed aby2503 closed 5 years ago

aby2503 commented 5 years ago

Steps to reproduce

Just try to run

PRODUCTION_USER="elixir.service" \ PRODUCTION_HOSTS="10.1.0.125" \ DELIVER_TO="/home/elixir.service/elixir_ci/service" \ MIX_ENV=prod \ APP=service \ mix edeliver restart production --debug

Verbose Logs

``` warning: the VM is running with native name encoding of latin1 which may cause Elixir to malfunction as it expects utf8. Please ensure your locale is set to UTF-8 (which can be verified by running "locale" in your shell) EDELIVER SERVICE WITH RESTART COMMAND -----> restarting staging servers staging node: user : elixir.service host : 10.1.0.125 path : /home/service/elixir_ci/service response: RESTART DONE! ```

Description of issue

[error] Connection to Mongo refused due to %MatchError{term: {:error, :econnrefused}}
%{db_name: "def_db", host: 'localhost', port: 27017} attempt 0
Path.join(["rel", "plugins", "*.exs"])
|> Path.wildcard()
|> Enum.map(&Code.eval_file(&1))

use Mix.Releases.Config,

  default_release: :default,

  default_environment: Mix.env()

environment :dev do
  set(dev_mode: true)
  set(include_erts: false)
  set(cookie: :"2xgsnHjQQ++73s5HQ4rB0Royj8gS1NO+ERF+RDAA/cdqmiXfnMhGwvinndXxK9Bx")
  plugin(Releases.Plugin.LinkConfig)
end

environment :stage do
  set(include_erts: true)
  set(include_src: false)
  set(cookie: :"2xgsnHjQQ++73s5HQ4rB0Royj8gS1NO+BW7+SDD/cdqmiXfnMhGwvinndXxK9Bx")
  set(run_erl_env: "RUN_ERL_LOG_MAXSIZE=50000000 RUN_ERL_LOG_GENERATIONS=50")
  plugin(Releases.Plugin.LinkConfig)
end

environment :prod do
  set(include_erts: true)
  set(include_src: false)
  set(cookie: :"3xgsfLjQQ++73s5HQ4rB0Royj8gS1NO+BW7+SDD/cdqmiXfnMhGwvinndXxJU0x")
  set(run_erl_env: "RUN_ERL_LOG_MAXSIZE=50000000 RUN_ERL_LOG_GENERATIONS=50")

  set(
    config_providers: [
      {Mix.Releases.Config.Providers.Elixir, ["${RELEASE_ROOT_DIR}/etc/config.exs"]}
    ]
  )

  set(overlays: [{:copy, "rel/config/<%= release_name %>/config.exs", "etc/config.exs"}])

  plugin(Releases.Plugin.LinkConfig)
end

release :service do
  set(version: current_version(:service))

  set(
    applications: [
      :service
      :runtime_tools
    ]
  )
end

SERVICE

config :service, Service.MongoDB, host: String.to_charlist(System.get_env("MONGO_HOST")), port: String.to_integer(System.get_env("MONGO_PORT")), db_name: System.get_env("MONGO_DB")

config :service, Service.NatsHandler, host: String.to_charlist(System.get_env("NATS_HOST")), port: String.to_integer(System.get_env("NATS_PORT"))

imranismail commented 5 years ago

Probably related to #568

I've attempted to fix this but I don't know where to even start

aby2503 commented 5 years ago

Probably related to #568

I've attempted to fix this but I don't know where to even start

I think, you should start from this function Elixir.Mix.Releases.Assembler - make_boot_scripts According to source code and distillery docs, all config providers invoked during runtime

# Generates .boot script
  defp make_boot_scripts(%Release{name: name, profile: profile} = release) do
    Shell.debug("Generating boot scripts")

    output_dir = profile.output_dir

    with {:ok, boot} <- BootScript.new(release) do
      # This boot script contains all applications, only starting the minimal set
      clean_boot =
        boot
        |> BootScript.start_only([:kernel, :stdlib, :compiler, :elixir])

      # The config boot is like the clean boot, but executes all config providers once started
      providers = release.profile.config_providers

      config_boot =
        clean_boot
        |> BootScript.after_started(:elixir, [
          {:apply, {Mix.Releases.Config.Provider, :init, [providers]}}
        ])

      # Finally, this is the "real" boot script for the app itself
      app_boot =
        boot
        |> BootScript.add_kernel_proc({Mix.Releases.Runtime.Pidfile, :start, []})

      rel_dir = Release.version_path(release)
      bin_dir = Path.join(output_dir, "bin")

      with :ok <- BootScript.write(app_boot),
           :ok <- BootScript.write(app_boot, :start),
           :ok <- BootScript.write(clean_boot, :start_clean),
           :ok <- BootScript.write(clean_boot, :no_dot_erlang),
           :ok <- BootScript.write(config_boot, :config),
           # These two need to be copied to bin/ for ERTS
           :ok <-
             File.cp(
               Path.join(rel_dir, "start_clean.boot"),
               Path.join(bin_dir, "start_clean.boot")
             ),
           :ok <-
             File.cp(
               Path.join(rel_dir, "no_dot_erlang.boot"),
               Path.join(bin_dir, "no_dot_erlang.boot")
             ),
           :ok <- create_RELEASES(output_dir, Path.join(rel_dir, "#{name}.rel")) do
        :ok
      end
    end
  end

After primary start, init method of Mix.Releases.Config.Provider invoked**. I think, by some circumstances, providers can be processed after loading

hauleth commented 5 years ago

I have added simple post_configure hook that waits 1 second before continuing. I have tested it and so far it works as a workaround.

aby2503 commented 5 years ago

Actually, I did the same thing.

imranismail commented 5 years ago

post_configure

I'll give this a shot. Many thanks!