./ct_report/coverage/mod_global_distrib_hosts_refresher.COVER.html

1 %%%==============================================================================
2 %% Copyright 2018 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
17
18 -module(mod_global_distrib_hosts_refresher).
19 -author("dominik.stanaszek@erlang-solutions.com").
20
21 -behaviour(gen_server).
22 -behaviour(gen_mod).
23 -behaviour(mongoose_module_metrics).
24
25 -include("mongoose.hrl").
26
27 %% API
28 -export([start_link/1]).
29
30 %% gen_server API
31 -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
32
33 %% gen_mod API
34 -export([deps/2, start/2, stop/1]).
35
36 %% Test & debug API
37 -export([pause/0, unpause/0]).
38
39 -ignore_xref([pause/0, start_link/1, unpause/0]).
40
41 -record(state, {local_host :: binary(),
42 refresh_interval :: pos_integer(),
43 tref :: reference() | undefined}).
44
45 %%--------------------------------------------------------------------
46 %% API
47 %%--------------------------------------------------------------------
48
49 -spec start_link(gen_mod:module_opts()) -> pid() | term().
50 start_link(Opts) ->
51 21 gen_server:start_link({local, ?MODULE}, ?MODULE, Opts, []).
52
53 -spec pause() -> ok.
54 pause() ->
55 86 gen_server:call(?MODULE, pause).
56
57 -spec unpause() -> ok.
58 unpause() ->
59 86 gen_server:call(?MODULE, unpause).
60
61 %%--------------------------------------------------------------------
62 %% gen_mod callbacks
63 %%--------------------------------------------------------------------
64
65 -spec start(mongooseim:host_type(), gen_mod:module_opts()) -> any().
66 start(_HostType, Opts) ->
67 21 start_outgoing_conns_sup(),
68 21 Child = #{
69 id => ?MODULE,
70 start => {?MODULE, start_link, [Opts]},
71 restart => transient,
72 shutdown => 5000,
73 modules => [?MODULE]
74 },
75 21 {ok, _} = supervisor:start_child(mod_global_distrib_outgoing_conns_sup, Child),
76 21 ok.
77
78 -spec stop(mongooseim:host_type()) -> any().
79 stop(_HostType) ->
80 21 stop_outgoing_conns_sup(),
81 21 ok.
82
83 -spec deps(mongooseim:host_type(), gen_mod:module_opts()) -> gen_mod_deps:deps().
84 deps(_HostType, Opts) ->
85 106 [{mod_global_distrib_utils, Opts, hard},
86 {mod_global_distrib_mapping, Opts, hard}].
87
88 %%--------------------------------------------------------------------
89 %% gen_server callbacks
90 %%--------------------------------------------------------------------
91
92 init(#{local_host := LocalHost, hosts_refresh_interval := RefreshInterval}) ->
93 21 ?LOG_DEBUG(#{what => gd_refresher_started, refresh_interval => RefreshInterval}),
94 21 NState = schedule_refresh(#state{local_host = LocalHost,
95 refresh_interval = RefreshInterval}),
96 21 {ok, NState}.
97
98 handle_call(pause, _From, State = #state{tref = undefined}) ->
99
:-(
?LOG_ERROR(#{what => gd_refresher_already_paused}),
100
:-(
{reply, ok, State};
101 handle_call(pause, _From, State) ->
102 86 erlang:cancel_timer(State#state.tref),
103 86 {reply, ok, State#state{ tref = undefined }};
104 handle_call(unpause, _From, State = #state{tref = undefined}) ->
105 86 {reply, ok, schedule_refresh(State)};
106 handle_call(unpause, _From, State = #state{tref = TRef}) ->
107
:-(
?LOG_ERROR(#{what => gd_refresher_already_running, timer_ref => TRef,
108
:-(
text => <<"GD Refresher received unpause, when already unpaused. Ignore.">>}),
109
:-(
{reply, ok, State};
110 handle_call(Request, From, State) ->
111
:-(
?UNEXPECTED_CALL(Request, From),
112
:-(
{reply, {error, unknown_request}, State}.
113
114 handle_cast(Request, State) ->
115
:-(
?UNEXPECTED_CAST(Request),
116
:-(
{noreply, State}.
117
118 handle_info({timeout, TRef, refresh}, #state{local_host = LocalHost, tref = TRef} = State) ->
119 597 refresh(LocalHost),
120 597 NState = schedule_refresh(State),
121 597 {noreply, NState, hibernate};
122 handle_info({timeout, _, refresh}, State) ->
123 %% We got refresh signal from outdated timer
124
:-(
{noreply, State, hibernate};
125 handle_info(Msg, State) ->
126
:-(
?UNEXPECTED_INFO(Msg),
127
:-(
{noreply, State, hibernate}.
128
129 terminate(Reason, _State) ->
130
:-(
?LOG_INFO(#{what => gd_refresher_stopped, reason => Reason,
131
:-(
text => <<"mod_global_distrib_refresher has terminated">>}).
132
133
:-(
code_change(_, State, _) -> {ok, State}.
134
135 %%--------------------------------------------------------------------
136 %% Helper functions
137 %%--------------------------------------------------------------------
138
139 refresh(LocalHost) ->
140 597 Hosts = mod_global_distrib_mapping:hosts(),
141 597 ?LOG_DEBUG(#{what => gd_refresher_fetched_hosts,
142 597 hosts => Hosts, local_host => LocalHost}),
143 597 lists:foreach(fun mod_global_distrib_outgoing_conns_sup:ensure_server_started/1,
144 lists:delete(LocalHost, Hosts)).
145
146 schedule_refresh(#state{ refresh_interval = Interval } = State) ->
147 704 TRef = erlang:start_timer(Interval, self(), refresh),
148 704 State#state{ tref = TRef }.
149
150 start_outgoing_conns_sup() ->
151 21 ConnsSup = mod_global_distrib_outgoing_conns_sup,
152 21 ChildSpec = #{
153 id => ConnsSup,
154 start => {ConnsSup, start_link, []},
155 restart => permanent,
156 shutdown => 5000,
157 type => supervisor,
158 modules => [ConnsSup]
159 },
160 21 ejabberd_sup:start_child(ChildSpec).
161
162 stop_outgoing_conns_sup() ->
163 21 ConnsSup = mod_global_distrib_outgoing_conns_sup,
164 21 ejabberd_sup:stop_child(ConnsSup).
Line Hits Source