Current section
Files
Jump to
Current section
Files
src/epgpool_alive.erl
-module(epgpool_alive).
-behaviour(gen_server).
-export([
start_link/1
]).
-export([
init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
terminate/2,
code_change/3
]).
-record(state, {
fails = 0 :: non_neg_integer(),
status :: atom(),
connection :: epgpool:connection() | undefined,
opts :: [{atom(), any()}]
}).
-define(FAILS, 3).
start_link(Opts) ->
gen_server:start_link(?MODULE, Opts, []).
%%===================================================================
%% gen_server callbacks
%%===================================================================
init(Opts) ->
self() ! init,
process_flag(trap_exit, true),
{ok, #state{opts=Opts}}.
handle_call(_Request, _From, State) ->
{noreply, State, timeout()}.
handle_cast(_Msg, State) ->
{noreply, State, timeout()}.
handle_info(Msg, #state{fails=?FAILS, status=Status}=State) ->
ok = lager:error("Network problem was detected: (~p)", [Status]),
epgpool:kill_all_workers(),
handle_info(Msg, State#state{fails=0, status=kill});
handle_info(init, #state{opts=Opts, fails=Fails}=State) ->
StateR = try epgpool_worker:connect(Opts) of {ok, C} ->
State#state{fails=0, connection=C, status=init}
catch _C:_E ->
State#state{connection=undefined, fails=Fails+1, status=no_init}
end,
{noreply, StateR, timeout()};
handle_info({pgsql, C, {notice, _Error}}, #state{connection=C, fails=Fails}=State) ->
ok = epgsql:close(C),
State2 = State#state{connection=undefined, fails=Fails+1, status=notice},
handle_info(init, State2);
handle_info({'EXIT', C, _Error}, #state{connection=C, fails=Fails}=State) ->
State2 = State#state{connection=undefined, fails=Fails+1, status=exit},
handle_info(init, State2);
handle_info({'EXIT', _Pid, _Error}, State) ->
{noreply, State, timeout()};
handle_info(timeout, #state{connection=undefined}=State) ->
handle_info(init, State);
handle_info(timeout, #state{connection=C, fails=Fails}=State) ->
try
{ok, [], []} = gen_server:call(C, {squery, ""}),
{noreply, State#state{fails=0, status=alive}, timeout()}
catch _:_ ->
true = exit(C, kill),
State2 = State#state{
connection=undefined,
fails=Fails+1,
status=timeout
},
{noreply, State2, timeout()}
end;
handle_info(_Info, State) ->
{noreply, State, timeout()}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%===================================================================
%% Internal functions
%%===================================================================
-spec timeout() -> timeout().
timeout() ->
{ok, Timeout} = application:get_env(epgpool, database_retry_sleep),
Timeout.