Browse Source

exponential backoff for reconnect

Yuriy Zhloba 9 years ago
parent
commit
057d739969
5 changed files with 31 additions and 28 deletions
  1. 3 1
      Makefile
  2. 1 2
      include/epgsql_pool.hrl
  3. 1 1
      src/epgsql_pool_settings.erl
  4. 17 23
      src/epgsql_pool_utils.erl
  5. 9 1
      src/epgsql_pool_worker.erl

+ 3 - 1
Makefile

@@ -6,7 +6,9 @@ run:
 	erl -pa ebin -pa deps/*/ebin -boot start_sasl -s epgsql_pool_app test_run
 
 
-ct:
+tests:
+	rebar compile skip_deps=true
+	rebar eunit skip_deps=true
 	rebar ct skip_deps=true
 
 

+ 1 - 2
include/epgsql_pool.hrl

@@ -10,6 +10,5 @@
 -record(epgsql_connection, {
     sock :: pid(),
     params :: #epgsql_connection_params{},
-    reconnect_attempt = 0 :: non_neg_integer(),
-    reconnect_timeout = 0 :: non_neg_integer()
+    reconnect_attempt = 0 :: non_neg_integer()
 }).

+ 1 - 1
src/epgsql_pool_settings.erl

@@ -54,7 +54,7 @@ init([]) ->
     ets:insert(T, {{settings, connection_timeout}, 10000}),
     ets:insert(T, {{settings, query_timeout}, 10000}),
     ets:insert(T, {{settings, pooler_get_worker_timeout}, 1000}),
-    ets:insert(T, {{settings, max_reconnect_timeout}, 3000}),
+    ets:insert(T, {{settings, max_reconnect_timeout}, 5000}),
     ets:insert(T, {{settings, min_reconnect_timeout}, 100}),
     {ok, T}.
 

+ 17 - 23
src/epgsql_pool_utils.erl

@@ -35,29 +35,23 @@ close_connection(#epgsql_connection{sock = Sock} = Connection) ->
 
 
 -spec reconnect(#epgsql_connection{}) -> #epgsql_connection{}.
-reconnect(#epgsql_connection{reconnect_attempt = Attempt,
-                             reconnect_timeout = Timeout0} = Connection) ->
-    MaxReconnectTimeout = epgsql_pool_settings:get(max_reconnect_timeout),
-    MinReconnectTimeout = epgsql_pool_settings:get(min_reconnect_timeout),
-    Timeout = if
-                  Timeout0 > MaxReconnectTimeout -> Timeout0;
-                  true -> exponential_backoff(Attempt, MinReconnectTimeout)
-              end,
-    reconnect_after(Attempt, MinReconnectTimeout, Timeout),
-    Connection#epgsql_connection{reconnect_attempt = Attempt + 1, reconnect_timeout = Timeout}.
-
-
--spec reconnect_after(integer(), integer(), integer()) -> ok.
-reconnect_after(Attempt, TMin, TMax) ->
-    Delay = max(random:uniform(TMax), TMin),
-    error_logger:warning_msg("epgsql_pool reconnect after ~p attempt ~p", [Delay, Attempt]),
-    erlang:send_after(Delay, self(), open_connection),
-    ok.
-
-
--spec exponential_backoff(integer(), integer()) -> integer().
-exponential_backoff(N, T) ->
-    erlang:round(math:pow(2, N)) * T.
+reconnect(#epgsql_connection{reconnect_attempt = Attempt} = Connection) ->
+    MaxTimeout = epgsql_pool_settings:get(max_reconnect_timeout),
+    MinTimeout = epgsql_pool_settings:get(min_reconnect_timeout),
+    Timeout = exponential_backoff(Attempt, 10, MinTimeout, MaxTimeout),
+    error_logger:info_msg("epgsql_pool reconnect after ~p attempt ~p", [Timeout, Attempt]),
+    erlang:send_after(Timeout, self(), open_connection),
+    Connection#epgsql_connection{reconnect_attempt = Attempt + 1}.
+
+
+-spec exponential_backoff(integer(), integer(), integer(), integer()) -> integer().
+exponential_backoff(Attempt, MaxAttempt, _BaseTimeout, MaxTimeout) when Attempt >= MaxAttempt ->
+    Half = MaxTimeout div 2,
+    Half + random:uniform(Half);
+exponential_backoff(Attempt, _MaxAttempt, BaseTimeout, MaxTimeout) ->
+    Timeout = min(erlang:round(math:pow(2, Attempt) * BaseTimeout), MaxTimeout),
+    Half = Timeout div 2,
+    Half + random:uniform(Half).
 
 
 -spec pool_name_to_atom(epgsql_pool:pool_name()) -> atom().

+ 9 - 1
src/epgsql_pool_worker.erl

@@ -24,8 +24,11 @@ start_link(PoolName0) ->
 
 -spec init(gs_args()) -> gs_init_reply().
 init(PoolName) ->
-    process_flag(trap_exit, true),
     error_logger:info_msg("Init epgsql pool worker: ~p", [PoolName]),
+    process_flag(trap_exit, true),
+
+    random:seed(now()),
+
     self() ! open_connection,
     {ok, #state{pool_name = PoolName}}.
 
@@ -69,6 +72,11 @@ handle_info(open_connection, #state{pool_name = PoolName, connection = Connectio
             {noreply, State#state{connection = Connection4}}
     end;
 
+handle_info({'EXIT', _Sock, normal},
+            #state{connection = #epgsql_connection{sock = undefined}} = State) ->
+    do_nothing,
+    {noreply, State};
+
 handle_info({'EXIT', Sock, Reason},
             #state{connection = #epgsql_connection{sock = Sock} = Connection} = State) ->
     error_logger:error_msg("DB Connection ~p EXIT with reason: ~p", [Sock, Reason]),