rebar3,主管,行为(应用程序)

rebar3, supervisor, behaviour(application)

我有以下简单的 UDP 服务器:

现在,我的对等 UDP 客户端将故意发送格式错误的数据。

我可以编写一个 case 子句来匹配任何消息并忽略任何消息 消息格式错误。

但是,如果最终出现错误,它对我没有帮助。

我在某处读到:“不要防御性编程,让它崩溃,然后修复它”。

    =ERROR REPORT==== 19-Jul-2020::21:15:29.872000 ===
    Error in process <0.93.0> with exit value:
    {{case_clause,<<0>>},[{server,loop,1,[{file,"server.erl"},{line,16}]}]}

太棒了,它崩溃了,但我希望我的服务器现在自动重启:-)

我读到一个名为“supervisor”的进程可以监控我的 服务器并在检测到它死亡时重新启动它。

所以,我使用了“rebar3”,因为它在我编译时帮了我很多 几个文件只有 1 行 'rebar3 compile'.

它会自动创建一个包含 3 个文件的 /src/,但只有 2 个是 现在让我感兴趣:

另外,文档我也看过了,但理解起来还差得远

谁能指点一下,或者改造一下我的19行代码server.erl server_app.erl 并由 server_sup.erl?

监督

N.B:我不是在找 gen_server,我经常看到它,但我是吗 也有义务将其转换为 gen_server,或仅 application+supervisor 可以满足我的要求吗?

提前致谢,

此致,

Supervisors are part of the OTP supervision tree, which handles all the restart policies and such. Although it's possible not to use gen_servers for its modules, I'd avise against it: gen_servers provide a handy abstraction for the most common server operations (and they handle name registering, sys 消息和开箱即用的其他好东西)。

虽然 'let it crash' 引理在 Erlang 中很常见,但这并不意味着您不必预见代码可能面临的问题或者您只关心快乐的情况。我不想看到任何系统因某人的 malformed/malicious nc -u.

而崩溃

请记住,如果达到 supervisor 的重启限制,它也会死掉,最终到达应用程序的顶级 supervisor,这会导致 VM 在死后崩溃。

让我们来看看代码(对 rebar3 new app 生成的内容进行很少的编辑):

应用程序不需要版本:

-module(server_app).

-behaviour(application).
-export([start/2, stop/1]).

start(_StartType, _StartArgs) ->
    server_sup:start_link().

stop(_State) ->
    ok.

supervisor配置多一点,仅此而已:

-module(server_sup).

-behaviour(supervisor).
-export([start_link/0]).
-export([init/1]).

start_link() ->
    supervisor:start_link(?MODULE, []).

init([]) ->
    SupFlags = #{strategy => one_for_all,
                 intensity => 0,
                 period => 1},
    ChildSpecs = [#{id => my_server,
                    start => {server, start_link, [12345]},
                    type => worker
                   }],
    {ok, {SupFlags, ChildSpecs}}.

并且 server.erl 需要在启动函数中进行一些修改:

-module(server).
-export([start_link/1]).

start_link(Port) ->
    {ok, spawn_link(fun()->run_it(Port) end)}.

run_it(Port) ->
    {ok, Skt} = gen_udp:open(Port, [binary]),
    loop(Skt).

loop(Skt) ->
    receive
        {udp, Skt, _, _, Bin} ->
            case Bin of
                <<0:32>> ->
                    io:fwrite("~p~n", [{"Good Format: ", Bin}]),
                    loop(Skt)
            end

作为 gen_serverserver.erl 类似于:

-module(server).

-export([start_link/1]).

-behaviour(gen_server).
-export([
         init/1,
         handle_cast/2,
         handle_call/3,
         handle_info/2
        ]).

start_link(Port) ->
    gen_server:start_link(?MODULE, Port, []).

init(Port) ->
    gen_udp:open(Port, [binary]).

handle_call(_Call, _From, State) ->
    {reply, ok, State}.

handle_cast(_Msg, State) ->
    {noreply, State}.

handle_info({udp, Skt, _, _, Bin}, Skt) ->
    case Bin of
        <<0:32>> -> io:fwrite("~p~n", [{"Good Format: ", Bin}])
    end,
    {noreply, Skt};
handle_info(_Msg, State) -> % Messages that are not {udp, Skt, _, _, _} are discarded
    {noreply, State}.