【问题标题】:worker exits after starting in Supervisor工人在主管中启动后退出
【发布时间】:2019-09-29 03:59:13
【问题描述】:

我正在尝试在我在 mix.exs 的应用程序模块中调用的主管中启动以下工作人员

这样

defmodule AppStarter do
import Supervisor.Spec
def start(_type,_args) do
    children=[
        worker(TPMod1,[],[]),
        worker(TPMod2,[],[])
    ]
    opts=[strategy: :one_for_one, name: HelloVisor]
    Supervisor.start_link(children,opts)
end


end

我的一个模块是 GenServer,另一个我保留了一个简单的监听过程。

defmodule TPMod1 do

def start_link() do
 IO.puts "started TPMod1"
 listen()
end



def listen() do
  receive do
    _ -> :ok
  end
  listen()
end

 def child_spec(opts) do
      %{
        id: __MODULE__,
        start: {__MODULE__, :start_link, []},
        type: :worker,
        restart: :permanent,
        shutdown: 500
      }
    end


end

问题是它卡住并且没有启动worker 2 TPMod2 我尝试在TPMod1start_link() 中做

def start_link() do
 IO.puts "started TPMod1"
 Task.async(&listen/0)
end

但这给了我这个

** (Mix) 无法启动应用程序 tproject: AppStarter.start(:normal, []) 返回错误:shutdown: failed to 开始孩子:TPMod1 ** (EXIT) %Task{owner: #PID, pid: #PID, ref: #Reference}

我可以让它成为 GenServer 并让它工作,但是我们如何启动一个简单的 worker?为什么主管不再重新启动它?不是无限次,而是有时?它至少应该尝试重新启动并失败。如果有的话,请提出其他改进建议。

【问题讨论】:

    标签: elixir gen-server erlang-supervisor


    【解决方案1】:

    主管希望孩子们返回{:ok, pid}:ignore{:error, reason}

    它挂起是因为当主管在您的工作人员上运行start_link 函数时,它(作为他自己)执行listen,它设置了一个receive 块,所以它卡在那里。当您使用 gen_* 模块的 start_link 和朋友时,它会负责生成、正确返回等。

    在你的情况下,你可以切换:

    def start_link() do
     IO.puts "started TPMod1"
     listen()
    end
    

    到:

    def start_link() do
     pid = spawn(__MODULE__, :listen, [])
     {:ok, pid}
    end
    

    应该这样做。

    【讨论】:

    • 酷!那么总是使用 gen_* 而不是简单的 spawn 和 return 是一种好习惯吗?
    • @YugandharChaudhari 我认为在 99% 的常规情况下,确实没有理由不使用现有的 OTP 行为,因为它满足了主管等的期望,而对于原始流程,如果你必须实施这些行为希望它是OTP。有时 gen_server 太多(但任何具有一点结构的进程都非常适合),您可以使用 Tasks 之类的东西(通过不同的模式,如 async_nolink 等)非常适合其他 OTP 行为,例如 gen_servers 并且可以生成从他们内部,或从外部等待,等等。当然这一切都取决于......
    • 酷!那么总是使用 gen_* [behaviors] 而不是简单的 spawn 和 return 是一种好的做法吗? -- 这不仅仅是一种好的做法——它是唯一的做法。有一次,我试图弄清楚如何使用 Supervisor 启动任意进程,并且在 erlang 中进行了很多挖掘,最终发现不能使用 Supervisor 启动任意进程。主管期望它启动的进程是 OTP Applications, ...
    • ....这意味着工人必须定义某些功能,并且这些功能必须返回主管期望的某些值...这就是主管能够与工人。这里有更多信息:elixir-lang.org/getting-started/mix-otp/…
    • 还有:Supervisor.Spec --This module is deprecated. Use the new child specifications outlined in the Supervisor module instead.Supervisor module
    猜你喜欢
    • 2016-08-16
    • 1970-01-01
    • 1970-01-01
    • 2014-11-27
    • 2011-08-13
    • 1970-01-01
    • 2017-09-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多