在监督过程中异步执行功能

时间:2018-02-13 07:12:12

标签: elixir

我试图同时监控多个API。目前我正在启动我的应用程序,然后启动我的主管,然后启动监控过程。我虚弱的大脑已经设法达到我产生所有4个子进程的程度。

我的APIMon.Monitor模块很乱,我不确定如何修复它。我想要的是每个人都作为主管的孩子开始,然后无限期地在他们自己的scan()循环中运行,同时所有信息都独立地输出到控制台。

我已经玩了一段时间并试图通过任务文档,我似乎无法找到一种方法让这项工作完全阻止我的控制台在iex -S mix中,我认为这意味着我完全阻止了。我希望能够在这些任务正在运行或休眠时在控制台中执行命令。

非常感谢任何帮助。

APIMon.ex

defmodule APIMon do
  @API [
     %{id: "A", host: '192.168.1.5', port: 3001},
     %{id: "B", host: '192.168.1.7', port: 3001},
     %{id: "C", host: '192.168.1.8', port: 3001},
     %{id: "D", host: '192.168.1.9', port: 3001}
  ]

  def start(_type, _args) do
    APIMon.Supervisor.start_link(@API)
  end
end

APIMon.Supervisor

defmodule APIMon.Supervisor do
  use Supervisor

  def start_link(args) do
    Supervisor.start_link(__MODULE__, args, name: __MODULE__)
  end

  def init(args) do
    children =
      args
      |> Enum.reduce([], fn child, acc ->
        acc =
          acc ++ [Supervisor.child_spec({APIMon.Monitor, child}, id: "Worker_#{child.id}")]
      end)

    Supervisor.init(children, strategy: :one_for_one)
  end
end

APIMon.Monitor

defmodule APIMon.Monitor do
  use GenServer

  def start_link(arg) do
    id = arg.id
    GenServer.start_link(__MODULE__, arg, name: :"#{__MODULE__} [#{id}]")
  end

  ## Callbacks

  def init(arg) do
    pid = Kernel.inspect(self())

    IO.puts "Adding API monitor #{arg.id} to the stack as #{pid}"

    scan()

    {:ok, arg}
  end

  def scan() do
    task = Task.async(fn ->
       #do individual API health checks here
     end)

    Task.await(task)
    :timer.sleep(2500)

    scan()
  end
end

1 个答案:

答案 0 :(得分:4)

APIMon.Monitor的问题是它无法从init返回 - 您正在进入无限循环调用scan()。你可以通过向本身发送消息来解决这个问题。

听起来有点神秘,所以让我给你举个例子:

defmodule APIMon.Monitor do
  use GenServer

  def start_link(arg) do
    id = arg.id
    GenServer.start_link(__MODULE__, arg, name: :"#{__MODULE__} [#{id}]")
  end

  ## Callbacks

  def init(arg) do
    pid = Kernel.inspect(self())

    IO.puts "Adding API monitor #{arg.id} to the stack as #{pid}"

    Process.send_after(self(), :scan, 2500)

    {:ok, arg}
  end

  def handle_info(:scan, state) do
    #do individual API health checks here

    Process.send_after(self(), :scan, 2500)

    {:noreply, state}
  end
end

除此之外,我不认为你的代码是一团糟 - 这是一个结构良好的Elixir / OTP代码!

希望有所帮助!