Elixir Supervisors - 您如何命名监督任务

kki*_*che 8 elixir erlang-otp erlang-supervisor

我真的在与Elixir主管挣扎,并弄清楚如何命名它们以便我可以使用它们.基本上,我只是想开始一个监督Task,我可以发送消息.

所以我有以下内容:

defmodule Run.Command do
  def start_link do
    Task.start_link(fn ->
      receive do
        {:run, cmd} -> System.cmd(cmd, [])
      end
    end)
  end
end
Run Code Online (Sandbox Code Playgroud)

项目入口点为:

defmodule Run do
  use Application

  # See http://elixir-lang.org/docs/stable/elixir/Application.html
  # for more information on OTP Applications
  def start(_type, _args) do
    import Supervisor.Spec, warn: false

    children = [
      # Define workers and child supervisors to be supervised
      worker(Run.Command, [])
    ]

    # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: Run.Command]
    Supervisor.start_link(children, opts)
  end
end
Run Code Online (Sandbox Code Playgroud)

在这一点上,我甚至不相信我正在使用正确的东西(Task特别是).基本上,我想要的只是在应用程序启动时生成一个进程或任务或GenServer或其他什么是正确的,我可以发送消息本质上是一个System.cmd(cmd, opts).我希望监督这项任务或过程.当我发送一条{:run, cmd, opts}消息,例如{:run, "mv", ["/file/to/move", "/move/to/here"]}我希望它生成一个新任务或进程来执行该命令.对于我的使用,我甚至不需要从任务中获得响应,我只需要它来执行.任何有关去哪里的指导都会有所帮助.我已经阅读了入门指南但老实说它让我更加困惑,因为当我尝试做的事情时,它永远不会像在应用程序中那样.

谢谢你的耐心.

bit*_*ker 8

我只想使用GenServer,设置如下:

defmodule Run do
  use Application

  def start(_, _) do
    import Supervisor.Spec, warn: false

    children = [worker(Run.Command, [])]
    Supervisor.start_link(children, strategy: :one_for_one)
  end
end

defmodule Run.Command do
  use GenServer

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

  def run(cmd, opts) when is_list(opts), do: GenServer.call(__MODULE__, {:run, cmd, opts})
  def run(cmd, _), do: GenServer.call(__MODULE__, {:run, cmd, []})

  def handle_call({:run, cmd, opts}, _from, state) do
    {:reply, System.cmd(cmd, opts), state}
  end
  def handle_call(request, from, state), do: super(request, from, state)
end
Run Code Online (Sandbox Code Playgroud)

然后,您可以向正在运行的进程发送执行命令,如下所示:

# If you want the result
{contents, _} = Run.Command.run("cat", ["path/to/some/file"])
# If not, just ignore it
Run.Command.run("cp", ["path/to/source", "path/to/destination"])
Run Code Online (Sandbox Code Playgroud)

基本上我们正在创建一个"单例"进程(只有一个进程可以使用给定的名称注册,我们正在使用模块的名称注册Run.Command进程,因此start_link在进程运行时任何连续调用都将失败.但是,这可以很容易地建立一个API(该run功能),它可以透明地在其他进程中执行命令,而无需知道这件事的调用过程.我以前callcast这里,但它是如果一个微不足道的变化你永远不会关心结果,也不希望调用进程被阻塞.

对于长期运行的东西,这是一个更好的模式.对于一次性的东西,Task使用起来更简单,更容易,但我更喜欢使用这样GenServer的全球流程.

  • 这是一个完美的解决方案.你不能命名任务的原因是因为如果你想发送消息......你不想再使用任务了. (3认同)