我正在尝试在监督树中实现套接字服务器。我已将以下内容添加到主要主管:
supervisor(AcceptorSup, [Application.get_env(:appname, :port)])
supervisor(Task.Supervisor, [[name: ClientSupervisor]])
这是AcceptorSup
模块
defmodule AcceptorSup do
use Supervisor
require Logger
def start_link(port) do
Supervisor.start_link __MODULE__, [port: port], name: __MODULE__
end
def init(args \\ []) do
port = Keyword.get args, :port, 8000
{:ok, socket} = :gen_tcp.listen port, active: false, reuseaddr: true, packet: :raw
Logger.info "Server started on port #{port}"
children = [
worker(Acceptor, [socket], function: :start)
]
num_childs = Application.get_env :appname, :acceptors_num, 50
for _ <- 1..num_childs do
Task.start fn ->
Supervisor.start_child AcceptorSup, []
end
end
supervise(children, strategy: :simple_one_for_one, max_restarts: 1000, max_seconds: 10)
end
end
以下是Acceptor
defmodule Acceptor do
require Logger
def start(socket) when is_port(socket) do
Task.start_link fn -> serve_client(socket) end
end
defp serve_client(socket) when is_port(socket) do
{:ok, client} = :gen_tcp.accept socket
Logger.info "A client connected #{address client}"
{:ok, pid} = Task.Supervisor.start_child ClientSupervisor, fn -> serve(client) end
:ok = :gen_tcp.controlling_process client, pid
Supervisor.start_child AcceptorSup, []
end
end
所以,我开始一个Task.Supervisor
来处理客户端,这很好。我还启动了一个类型simple_one_for_one
的主管来处理监听器。每个孩子等待连接,并在给出时,在任务主管中为客户生成任务并启动另一个孩子而不是自己。问题是如果客户端连接和断开连接的速率足够高,主管就会崩溃,因为它会达到max_restarts
和max_seconds
的值。我可以通过增加值来增加阈值,但它对我来说似乎不对。我正在寻找一种方法来处理客户端的连接和断开连接,而不是达到这些限制。
如何实现这一点,同时尊重监督树?我不想使用自定义流程管理,因为我几乎可以肯定这里有一些我不知道的东西。无论如何,Erlang / OTP旨在解决这些问题,对吗?