【问题标题】:Asynchronously executing functions in supervised processes在受监督的进程中异步执行功能
【发布时间】:2018-02-13 16:04:25
【问题描述】:

我正在尝试同时监控多个 API。目前我正在启动我的应用程序,这会导致我的主管启动,进而启动监控进程。我虚弱的大脑已经到了产生所有 4 个子进程的地步。

我的APIMon.Monitor 模块一团糟,我不确定如何修复它。我想要的是让它们中的每一个都作为 Supervisor 的子级开始,然后无限期地在它们自己的 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

【问题讨论】:

  • 请注意,没有理由调用 async 然后等待单个任务。它将与执行内联代码具有相同的效果。

标签: elixir


【解决方案1】:

你的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 代码!

希望有帮助!

【讨论】:

    猜你喜欢
    • 2015-06-12
    • 2014-09-12
    • 2023-03-14
    • 2020-11-07
    • 2019-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-01
    相关资源
    最近更新 更多