【问题标题】:Basic Elixir OTP server behaves oddly基本 Elixir OTP 服务器行为异常
【发布时间】:2017-01-26 11:25:19
【问题描述】:

我有这个代码,它是一个基本的 OTP 服务器:

defmodule Clients do
use Application  
require Logger


def stuff do
    Logger.debug "Clients.start/0"
   # {:ok, pid} = Task.Supervisor.start_child(Clients.TaskSupervisor, fn -> doclient end)
end

def doclient(port) do
    Logger.debug "Clients.doclient/0"

    {:ok, socket} = :gen_tcp.listen(port,[:binary, packet: :line, active: false, reuseaddr: true])

#if this is under 2000ms there the process exits with a shutdown error 
    :timer.sleep(1500)

end

def start(_type, _args) do
    import Supervisor.Spec
    Logger.debug "Clients.init/1"

    children = [
        supervisor(Task.Supervisor, [[name: Clients.TaskSupervisor]]),
        worker(Task, [Clients, :doclient, [4040]])
    ]
    opts = [strategy: :one_for_one, name: Clients.Supervisor]
    Supervisor.start_link(children, opts)
end

end

iex 的输出是:

iex(1)> Clients.start(1,2)

20:07:19.879 [debug] Clients.init/1

20:07:19.889 [debug] Clients.doclient/0
{:ok, #PID<0.141.0>}
iex(2)> 
20:07:21.402 [debug] Clients.doclient/0

20:07:22.909 [debug] Clients.doclient/0

20:07:24.413 [debug] Clients.doclient/0
** (EXIT from #PID<0.139.0>) shutdown

如果 doclient/1 计时器调用不到 2 秒,则会发生上述关闭,否则它会愉快地滴答作响。我不确定为什么?如果我想让 doclient/1 执行一些花费不到 2 秒的任意代码(这不是我想象的可靠时间段),这个调用总是会爆炸。

【问题讨论】:

    标签: elixir erlang-otp erlang-supervisor


    【解决方案1】:

    您正在使用 Task 作为您的工作人员。所以发生的情况是,一旦 Task 从睡眠中醒来,它就完成了它的工作并且该进程消失了。在您的主管规范中,您要求:

    children = [
      supervisor(Task.Supervisor, [[name: Clients.TaskSupervisor]]),
      worker(Task, [Clients, :doclient, [4040]])
    ]
    opts = [strategy: :one_for_one, name: Clients.Supervisor]
    Supervisor.start_link(children, opts)
    

    如果它完成或以任何方式消失,它会告诉 OTP 重新启动您的工作程序。所以在 1.5 秒(你的睡眠时间)之后,主管开始另一个任务。它在 5 秒内执行了 3 次。

    Supervisor.start_link 具有指定重启强度的默认选项。根据Supervisor.Spec.supervise/2 上的文档,默认设置是在 5 秒内最多重启 3 次。这就是为什么您的主管会以 1.5 秒的睡眠时间关闭并愉快地以 2 秒的间隔继续运行。

    总而言之,我认为你需要重新考虑这个监督树中任务的使用。由于您没有提及它是什么,因此无法猜测最适合您的用例。

    HTH

    【讨论】:

    • 因此,Task 是一个一次性的瞬态,开始和消失。因此,如果 t
    • 这不是问题。这正是你要求主管做的。此外,任务通常是一次性的。你可以根据自己的喜好制作它们。例如,如果您在 :timer.sleep() 之后立即调用 doclient(port),则任务将永远进行。并且主管不会重新启动它。
    猜你喜欢
    • 1970-01-01
    • 2018-11-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-16
    • 2015-04-06
    • 2021-06-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多