./ct_report/coverage/mod_global_distrib_server_sup.COVER.html

1 %%==============================================================================
2 %% Copyright 2017 Erlang Solutions Ltd.
3 %%
4 %% Licensed under the Apache License, Version 2.0 (the "License");
5 %% you may not use this file except in compliance with the License.
6 %% You may obtain a copy of the License at
7 %%
8 %% http://www.apache.org/licenses/LICENSE-2.0
9 %%
10 %% Unless required by applicable law or agreed to in writing, software
11 %% distributed under the License is distributed on an "AS IS" BASIS,
12 %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 %% See the License for the specific language governing permissions and
14 %% limitations under the License.
15 %%==============================================================================
16 -module(mod_global_distrib_server_sup).
17 -author('piotr.nosek@erlang-solutions.com').
18
19 -behaviour(supervisor).
20
21 -include("mongoose.hrl").
22
23 -export([start_link/1, init/1]).
24 -export([get_connection/1, is_available/1]).
25 -export([start_pool/4, stop_pool/2]).
26
27 -ignore_xref([start_link/1]).
28
29 %%--------------------------------------------------------------------
30 %% API
31 %%--------------------------------------------------------------------
32
33 -spec start_link(Server :: jid:lserver()) -> {ok, pid()} | {error, any()}.
34 start_link(Server) ->
35 79 SupName = mod_global_distrib_utils:server_to_sup_name(Server),
36 79 supervisor:start_link({local, SupName}, ?MODULE, [Server]).
37
38 -spec get_connection(Server :: jid:lserver()) -> {ok, pid()} | {error, not_available}.
39 get_connection(Server) ->
40 47 try mod_global_distrib_server_mgr:get_connection(Server)
41 %% Possible issues:
42 %% - {'EXIT', {noproc, _}}
43 %% - {case_clause,{'EXIT',{no_connections...
44 catch Class:Reason:Stacktrace ->
45 16 ?LOG_ERROR(#{what => gd_get_connection_failed, server => Server,
46
:-(
class => Class, reason => Reason, stacktrace => Stacktrace}),
47 %% May be caused by missing server_sup or missing connection manager
48 %% The former occurs when a process tries to send a message to Server
49 %% for the first time.
50 %% The latter occurs when some other process already started server_sup,
51 %% which hasn't started manager yet.
52 %% In both cases the caller should attempt to start server_sup,
53 %% so the main outgoing_conns_sup becomes a synchronisation point
54 %% because it's impossible to learn that the server_sup is `already_started`
55 %% without it finishing the init first (thus finishing the init of mgr as well).
56 %%
57 %% TODO: Write a test for it, once we establish a good way to reproduce
58 %% race conditions in tests!
59 16 {error, not_available}
60 end.
61
62 -spec is_available(Server :: jid:lserver()) -> boolean().
63 is_available(Server) ->
64 571 pong == mod_global_distrib_server_mgr:ping_proc(Server).
65
66 -spec start_pool(Supervisor :: pid(),
67 Endpoint :: mod_global_distrib_utils:endpoint(),
68 Server :: jid:lserver(),
69 ConnOpts :: map()) ->
70 {ok, atom(), pid()} | {error, any()}.
71 start_pool(Supervisor, Endpoint, Server, #{connections_per_endpoint := PoolSize}) ->
72 109 PoolRef = endpoint_to_atom(Endpoint),
73 109 PoolParams = [
74 PoolRef,
75 {mod_global_distrib_connection, start_link, [Endpoint, Server]},
76 [{pool_size, PoolSize}]
77 ],
78 109 PoolSpec = #{
79 id => Endpoint,
80 start => {cpool, new_pool_sup, PoolParams},
81 restart => temporary,
82 shutdown => 5000,
83 type => supervisor,
84 modules => dynamic
85 },
86 109 {ok, PoolPid} = supervisor:start_child(Supervisor, PoolSpec),
87 104 {ok, PoolRef, PoolPid}.
88
89 -spec stop_pool(Supervisor :: pid(), Endpoint :: mod_global_distrib_utils:endpoint()) ->
90 ok | {error, any()}.
91 stop_pool(Supervisor, Endpoint) ->
92 1 ok = supervisor:terminate_child(Supervisor, Endpoint),
93 1 supervisor:delete_child(Supervisor, Endpoint).
94
95 %%--------------------------------------------------------------------
96 %% supervisor callback
97 %%--------------------------------------------------------------------
98
99 init([Server]) ->
100 79 SupFlags = #{ strategy => rest_for_one, intensity => 5, period => 5 },
101 79 MgrName = mod_global_distrib_utils:server_to_mgr_name(Server),
102 79 ServerMgrSpec = #{
103 id => MgrName,
104 start => {mod_global_distrib_server_mgr, start_link, [Server, self()]},
105 restart => transient,
106 shutdown => 5000,
107 type => worker,
108 modules => dynamic
109 },
110 79 {ok, {SupFlags, [ServerMgrSpec]}}.
111
112 %%--------------------------------------------------------------------
113 %% Helpers
114 %%--------------------------------------------------------------------
115
116 -spec endpoint_to_atom(mod_global_distrib_utils:endpoint()) -> atom().
117 endpoint_to_atom({IP, Port}) ->
118 109 list_to_atom(inet:ntoa(IP) ++ "_" ++ integer_to_list(Port)).
Line Hits Source