无法启动子级:EvercamAdmin.Storage **(EXIT):badarg药剂

时间:2019-05-28 08:11:28

标签: elixir phoenix-framework

我已将GenServer添加为

defmodule EvercamAdmin.Storage do

  use GenServer
  require Logger

  def start_link(args) do
    GenServer.start_link(__MODULE__, [args])
  end

  def init(args) do
    Logger.info "Starting to create storage.json."
    {:ok, 1}
  end
end

我正在通过application.ex文件启动它,例如

  def start(_type, _args) do
    # List all child processes to be supervised
    children = [
      EvercamAdminWeb.Endpoint,
      {EvercamAdmin.Storage, []}
    ]

    opts = [strategy: :one_for_one, name: EvercamAdmin.Supervisor]
    Supervisor.start_link(children, opts)
  end

它工作正常,但是突然开始出现错误或** (EXIT) :badarg

我也尝试过更改.stark_link(__MODULE__, :ok, [args]),但是错误是相同的。

更新:整个错误消息

Erlang/OTP 21 [erts-10.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]

Compiling 2 files (.ex)
[info] Running EvercamAdminWeb.Endpoint with cowboy 2.6.1 at http://localhost:4000
[info] Starting to create storage.json.

[info] Application evercam_admin exited: EvercamAdmin.Application.start(:normal, []) returned an error: shutdown: failed to start child: EvercamAdmin.Storage
    ** (EXIT) :badarg
** (Mix) Could not start application evercam_admin: EvercamAdmin.Application.start(:normal, []) returned an error: shutdown: failed to start child: EvercamAdmin.Storage
    ** (EXIT) :badarg

更新:完整的EvercamAdmin.Storage模块

defmodule EvercamAdmin.Storage do

  use GenServer
  require Logger
  import Ecto.Query

  @seaweedfs_new Application.get_env(:evercam_admin, :seaweedfs_new)
  @seaweedfs_old Application.get_env(:evercam_admin, :seaweedfs_old)
  @seaweedfs_oldest Application.get_env(:evercam_admin, :seaweedfs_oldest)

  @proxy_host Application.get_env(:evercam_admin, :proxy_host)
  @proxy_pass Application.get_env(:evercam_admin, :proxy_pass)

  def start_link(args \\ []) do
    GenServer.start_link(__MODULE__, args)
  end

  def init(args) do
    Logger.info "Starting to create storage.json."
    check_for_online_json_file()
    |> whats_next(args)
    {:ok, 1}
  end

  defp whats_next(:ok, ["refresh"]), do: whats_next(:start, ["refresh"])
  defp whats_next(:ok, _), do: :noop
  defp whats_next(:start, _args) do
    construction_cameras =
      Camera
      |> where([cam], cam.owner_id  in [13959, 109148])
      |> preload(:owner)
      |> Evercam.Repo.all

    years = ["2015", "2016", "2017", "2018", "2019"]
    servers = [@seaweedfs_new, @seaweedfs_old, @seaweedfs_oldest]

    big_data =
      Enum.map(construction_cameras, fn camera ->
        servers =
          Enum.map(servers, fn server ->
            type = seaweefs_type(server)
            attribute = seaweedfs_attribute(server)
            url = "http://" <> server <> ":8888" <> "/#{camera.exid}/snapshots/recordings/"
            year_values =
              Enum.map(years, fn year ->
                final_url = url <> year <> "/"
                %{
                  "#{year}" => request_from_seaweedfs(final_url, type, attribute)
                }
              end)

            %{
              "#{server}" => year_values
            }
          end)
        %{
          camera_name: camera.name,
          camera_exid: camera.exid,
          oldest_snapshot_date: _snapshot_date(:oldest, camera),
          latest_snapshot_date: _snapshot_date(:latest, camera),
          servers: servers
        }
      end)
    File.write("storage.json", Poison.encode!(big_data), [:binary])
    seaweedfs_save(big_data, 1)
  end

  defp seaweefs_type(@seaweedfs_new), do: "Entries"
  defp seaweefs_type(_), do: "Directories"

  defp seaweedfs_attribute(@seaweedfs_new), do: "FullPath"
  defp seaweedfs_attribute(_), do: "Name"

  defp _snapshot_date(atom, camera) do
    with {:ok, %HTTPoison.Response{body: body, status_code: 200}} <- HTTPoison.get(
                                            "https://media.evercam.io/v2/cameras/#{camera.exid}/recordings/snapshots/#{atom |> to_string}?api_id=#{camera.owner.api_id}&api_key=#{camera.owner.api_key}"
                                            )
    do
      {:ok, %{"created_at" => date}} = Jason.decode(body)
      date
    else
      _ ->
        ""
    end
  end

  def check_for_online_json_file do
    with {:ok, %HTTPoison.Response{status_code: 200}} <- HTTPoison.get(
                              "http://#{@seaweedfs_new}:8888/evercam-admin3/storage.json",
                              ["Accept": "application/json"],
                              hackney: [pool: :seaweedfs_download_pool],
                              proxy: {@proxy_host, 80},
                              proxy_auth: {"fixie", @proxy_pass}
                            )
    do :ok
    else
      _ ->
        :start
    end

  end

  def request_from_seaweedfs(url, type, attribute) do
    hackney = [pool: :seaweedfs_download_pool, recv_timeout: 15000]
    with {:ok, response} <- HTTPoison.get(url, ["Accept": "application/json"], hackney: hackney, proxy: {@proxy_host, 80}, proxy_auth: {"fixie", @proxy_pass}),
         %HTTPoison.Response{status_code: 200, body: body} <- response,
         {:ok, data} <- Poison.decode(body),
         true <- is_list(data[type]) do
      Enum.map(data[type], fn(item) -> item[attribute] |> get_base_name(type, attribute) end)
    else
      _ -> []
    end
  end

  defp get_base_name(list, "Entries", "FullPath"), do: list |> Path.basename
  defp get_base_name(list, _, _), do: list

  def seaweedfs_save(_data, _tries = 4), do: :noop
  def seaweedfs_save(data, tries) do
    hackney = [pool: :seaweedfs_upload_pool]
    case HTTPoison.post("http://#{@seaweedfs_new}:8888/evercam-admin3/storage.json", {:multipart, [{"/evercam-admin3/storage.json", Jason.encode!(data), []}]}, [], hackney: hackney, proxy: {@proxy_host, 80}, proxy_auth: {"fixie", @proxy_pass}) do
      {:ok, response} -> response
      {:error, error} ->
        seaweedfs_save(data, tries + 1)
        Logger.info "[seaweedfs_save] [#{inspect error}]"
    end
  end
end

1 个答案:

答案 0 :(得分:0)

{EvercamAdmin.Storage, []}(基本上与EvercamAdmin.Storage相同)在调用Supervisor.start_link/2时的子参数告诉Supervisor调用EvercamAdmin.Storage.start_link/1 不带参数,而您的实现只需要一个参数(arity恰好是1。)

args通常是一团糟。您期望args,然后将其包装在一个列表中(目的是什么?),然后将其传递给init/1,以后再也不用。应该执行以下操作:

defmodule EvercamAdmin.Storage do
  use GenServer
  require Logger

  def start_link(args \\ []), # accept no params
    do: GenServer.start_link(__MODULE__, args)

  def init(args) do
    Logger.info "Starting to create storage.json."
    {:ok, args} # What did `1` suppose to mean?
  end
end

并致电Supervisor.start_link/2

children = [
  EvercamAdminWeb.Endpoint,
  EvercamAdmin.Storage # `start_link` now accepts empty args
]