Basic Elixir OTP 服务器行为异常
Basic Elixir OTP server behaves oddly
我有这个代码,它是一个基本的 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 秒的任意代码(无论如何这不是我想象的可靠时间段),这个调用总是会爆炸。
您正在使用 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
我有这个代码,它是一个基本的 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 秒的任意代码(无论如何这不是我想象的可靠时间段),这个调用总是会爆炸。
您正在使用 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