./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, {
42 refresh_interval :: pos_integer(),
43 tref :: reference() | undefined
44 }).
45
46 %%--------------------------------------------------------------------
47 %% API
48 %%--------------------------------------------------------------------
49
50 -spec start_link(Milliseconds :: non_neg_integer()) -> pid() | term().
51 start_link(RefreshInterval) ->
52 21 gen_server:start_link({local, ?MODULE}, ?MODULE, [RefreshInterval], []).
53
54 -spec pause() -> ok.
55 pause() ->
56 86 gen_server:call(?MODULE, pause).
57
58 -spec unpause() -> ok.
59 unpause() ->
60 86 gen_server:call(?MODULE, unpause).
61
62 %%--------------------------------------------------------------------
63 %% gen_mod callbacks
64 %%--------------------------------------------------------------------
65
66 -spec start(Host :: jid:lserver(), Opts :: proplists:proplist()) -> any().
67 start(Host, Opts0) ->
68 21 Opts = [{hosts_refresh_interval, default_refresh_interval()} | Opts0],
69 21 mod_global_distrib_utils:start(?MODULE, Host, Opts, fun start/0).
70
71 -spec stop(Host :: jid:lserver()) -> any().
72 stop(Host) ->
73 21 mod_global_distrib_utils:stop(?MODULE, Host, fun stop/0).
74
75 -spec deps(Host :: jid:server(), Opts :: proplists:proplist()) -> gen_mod:deps_list().
76 deps(Host, Opts) ->
77 107 mod_global_distrib_utils:deps(?MODULE, Host, Opts, fun deps/1).
78
79 %%--------------------------------------------------------------------
80 %% gen_server callbacks
81 %%--------------------------------------------------------------------
82
83 init([RefreshInterval]) ->
84 21 ?LOG_DEBUG(#{what => gd_refresher_started, refresh_interval => RefreshInterval}),
85 21 NState = schedule_refresh(#state{ refresh_interval = RefreshInterval }),
86 21 {ok, NState}.
87
88 handle_call(pause, _From, State = #state{tref = undefined}) ->
89
:-(
?LOG_ERROR(#{what => gd_refresher_already_paused}),
90
:-(
{reply, ok, State};
91 handle_call(pause, _From, State) ->
92 86 erlang:cancel_timer(State#state.tref),
93 86 {reply, ok, State#state{ tref = undefined }};
94 handle_call(unpause, _From, State = #state{tref = undefined}) ->
95 86 {reply, ok, schedule_refresh(State)};
96 handle_call(unpause, _From, State = #state{tref = TRef}) ->
97
:-(
?LOG_ERROR(#{what => gd_refresher_already_running, timer_ref => TRef,
98
:-(
text => <<"GD Refresher received unpause, when already unpaused. Ignore.">>}),
99
:-(
{reply, ok, State};
100 handle_call(Request, From, State) ->
101
:-(
?UNEXPECTED_CALL(Request, From),
102
:-(
{reply, {error, unknown_request}, State}.
103
104 handle_cast(Request, State) ->
105
:-(
?UNEXPECTED_CAST(Request),
106
:-(
{noreply, State}.
107
108 handle_info({timeout, TRef, refresh}, #state{ tref = TRef } = State) ->
109 1013 refresh(),
110 1013 NState = schedule_refresh(State),
111 1013 {noreply, NState, hibernate};
112 handle_info({timeout, _, refresh}, State) ->
113 %% We got refresh signal from outdated timer
114
:-(
{noreply, State, hibernate};
115 handle_info(Msg, State) ->
116
:-(
?UNEXPECTED_INFO(Msg),
117
:-(
{noreply, State, hibernate}.
118
119 terminate(Reason, _State) ->
120
:-(
?LOG_INFO(#{what => gd_refresher_stopped, reason => Reason,
121
:-(
text => <<"mod_global_distrib_refresher has terminated">>}).
122
123
:-(
code_change(_, State, _) -> {ok, State}.
124
125 %%--------------------------------------------------------------------
126 %% Helper functions
127 %%--------------------------------------------------------------------
128
129
130 -spec deps(Opts :: proplists:proplist()) -> gen_mod:deps_list().
131 deps(Opts) ->
132 107 [{mod_global_distrib_mapping, Opts, hard}].
133
134 -spec start() -> any().
135 start() ->
136 21 start_outgoing_conns_sup(),
137 21 Interval = mod_global_distrib_utils:opt(?MODULE, hosts_refresh_interval),
138 21 Child = #{
139 id => ?MODULE,
140 start => {?MODULE, start_link, [Interval]},
141 restart => transient,
142 shutdown => 5000,
143 modules => [?MODULE]
144 },
145 21 {ok, _} = supervisor:start_child(mod_global_distrib_outgoing_conns_sup, Child),
146 21 ok.
147
148 -spec stop() -> any().
149 stop() ->
150 21 stop_outgoing_conns_sup(),
151 21 ok.
152
153 refresh() ->
154 1013 Hosts = mod_global_distrib_mapping:hosts(),
155 1013 LocalHost = local_host(),
156 1013 ?LOG_DEBUG(#{what => gd_refresher_fetched_hosts,
157 1013 hosts => Hosts, local_host => LocalHost}),
158 1013 lists:foreach(fun mod_global_distrib_outgoing_conns_sup:ensure_server_started/1,
159 lists:delete(LocalHost, Hosts)).
160
161 schedule_refresh(#state{ refresh_interval = Interval } = State) ->
162 1120 TRef = erlang:start_timer(Interval, self(), refresh),
163 1120 State#state{ tref = TRef }.
164
165 default_refresh_interval() ->
166 21 3000.
167
168 local_host() ->
169 1013 mod_global_distrib_utils:opt(?MODULE, local_host).
170
171 start_outgoing_conns_sup() ->
172 21 ConnsSup = mod_global_distrib_outgoing_conns_sup,
173 21 ChildSpec = #{
174 id => ConnsSup,
175 start => {ConnsSup, start_link, []},
176 restart => permanent,
177 shutdown => 5000,
178 type => supervisor,
179 modules => [ConnsSup]
180 },
181 21 ejabberd_sup:start_child(ChildSpec).
182
183
184 stop_outgoing_conns_sup() ->
185 21 ConnsSup = mod_global_distrib_outgoing_conns_sup,
186 21 ejabberd_sup:stop_child(ConnsSup).
Line Hits Source