25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-10-31 15:21:38 +01:00

Merge 2427 from trunk: return timeout in requests if DB connection can't be established

SVN Revision: 2511
This commit is contained in:
Badlop 2009-08-20 17:37:37 +00:00
parent 05755b9b09
commit ec26a28cd2
2 changed files with 43 additions and 18 deletions

View File

@ -58,7 +58,7 @@
-define(PGSQL_PORT, 5432). -define(PGSQL_PORT, 5432).
-define(MYSQL_PORT, 3306). -define(MYSQL_PORT, 3306).
-define(TRANSACTION_TIMEOUT, 60000). -define(TRANSACTION_TIMEOUT, 60000). % milliseconds
-define(KEEPALIVE_TIMEOUT, 60000). -define(KEEPALIVE_TIMEOUT, 60000).
-define(KEEPALIVE_QUERY, "SELECT 1;"). -define(KEEPALIVE_QUERY, "SELECT 1;").
@ -150,24 +150,30 @@ escape_like(C) -> odbc_queries:escape(C).
init([Host, StartInterval]) -> init([Host, StartInterval]) ->
case ejabberd_config:get_local_option({odbc_keepalive_interval, Host}) of case ejabberd_config:get_local_option({odbc_keepalive_interval, Host}) of
KeepaliveInterval when is_integer(KeepaliveInterval) -> KeepaliveInterval when is_integer(KeepaliveInterval) ->
timer:apply_interval(KeepaliveInterval*1000, ?MODULE, keep_alive, [self()]); timer:apply_interval(KeepaliveInterval*1000, ?MODULE,
keep_alive, [self()]);
undefined -> undefined ->
ok; ok;
_Other -> _Other ->
?ERROR_MSG("Wrong odbc_keepalive_interval definition '~p' for host ~p.~n", [_Other, Host]) ?ERROR_MSG("Wrong odbc_keepalive_interval definition '~p'"
" for host ~p.~n", [_Other, Host])
end, end,
SQLServer = ejabberd_config:get_local_option({odbc_server, Host}), SQLServer = ejabberd_config:get_local_option({odbc_server, Host}),
case SQLServer of case SQLServer of
%% Default pgsql port %% Default pgsql port
{pgsql, Server, DB, Username, Password} -> {pgsql, Server, DB, Username, Password} ->
pgsql_connect(Server, ?PGSQL_PORT, DB, Username, Password, StartInterval); pgsql_connect(Server, ?PGSQL_PORT, DB, Username, Password,
StartInterval);
{pgsql, Server, Port, DB, Username, Password} when is_integer(Port) -> {pgsql, Server, Port, DB, Username, Password} when is_integer(Port) ->
pgsql_connect(Server, Port, DB, Username, Password, StartInterval); pgsql_connect(Server, Port, DB, Username, Password,
StartInterval);
%% Default mysql port %% Default mysql port
{mysql, Server, DB, Username, Password} -> {mysql, Server, DB, Username, Password} ->
mysql_connect(Server, ?MYSQL_PORT, DB, Username, Password, StartInterval); mysql_connect(Server, ?MYSQL_PORT, DB, Username, Password,
StartInterval);
{mysql, Server, Port, DB, Username, Password} when is_integer(Port) -> {mysql, Server, Port, DB, Username, Password} when is_integer(Port) ->
mysql_connect(Server, Port, DB, Username, Password, StartInterval); mysql_connect(Server, Port, DB, Username, Password,
StartInterval);
_ when is_list(SQLServer) -> _ when is_list(SQLServer) ->
odbc_connect(SQLServer, StartInterval) odbc_connect(SQLServer, StartInterval)
end. end.
@ -270,7 +276,8 @@ inner_transaction(F) ->
case get(?NESTING_KEY) of case get(?NESTING_KEY) of
?TOP_LEVEL_TXN -> ?TOP_LEVEL_TXN ->
{backtrace, T} = process_info(self(), backtrace), {backtrace, T} = process_info(self(), backtrace),
?ERROR_MSG("inner transaction called at outer txn level. Trace: ~s", [T]), ?ERROR_MSG("inner transaction called at outer txn level. Trace: ~s",
[T]),
erlang:exit(implementation_faulty); erlang:exit(implementation_faulty);
_N -> ok _N -> ok
end, end,
@ -295,7 +302,8 @@ outer_transaction(F, NRestarts, _Reason) ->
ok; ok;
_N -> _N ->
{backtrace, T} = process_info(self(), backtrace), {backtrace, T} = process_info(self(), backtrace),
?ERROR_MSG("outer transaction called at inner txn level. Trace: ~s", [T]), ?ERROR_MSG("outer transaction called at inner txn level. Trace: ~s",
[T]),
erlang:exit(implementation_faulty) erlang:exit(implementation_faulty)
end, end,
sql_query_internal("begin;"), sql_query_internal("begin;"),
@ -329,7 +337,8 @@ outer_transaction(F, NRestarts, _Reason) ->
end. end.
execute_bloc(F) -> execute_bloc(F) ->
%% We don't alter ?NESTING_KEY here as only SQL transactions alter txn nesting %% We don't alter ?NESTING_KEY here as only SQL transactions alter
%% txn nesting
case catch F() of case catch F() of
{aborted, Reason} -> {aborted, Reason} ->
{aborted, Reason}; {aborted, Reason};
@ -348,7 +357,8 @@ sql_query_internal(Query) ->
pgsql_to_odbc(pgsql:squery(State#state.db_ref, Query)); pgsql_to_odbc(pgsql:squery(State#state.db_ref, Query));
mysql -> mysql ->
?DEBUG("MySQL, Send query~n~p~n", [Query]), ?DEBUG("MySQL, Send query~n~p~n", [Query]),
R = mysql_to_odbc(mysql_conn:fetch(State#state.db_ref, Query, self())), R = mysql_to_odbc(mysql_conn:fetch(State#state.db_ref,
Query, self())),
?INFO_MSG("MySQL, Received result~n~p~n", [R]), ?INFO_MSG("MySQL, Received result~n~p~n", [R]),
R R
end, end,
@ -441,7 +451,8 @@ mysql_connect(Server, Port, DB, Username, Password, StartInterval) ->
mysql_conn:fetch(Ref, ["set names 'utf8';"], self()), mysql_conn:fetch(Ref, ["set names 'utf8';"], self()),
{ok, #state{db_ref = Ref, db_type = mysql}}; {ok, #state{db_ref = Ref, db_type = mysql}};
{error, Reason} -> {error, Reason} ->
?ERROR_MSG("MySQL connection failed: ~p~nWaiting ~p seconds before retrying...~n", ?ERROR_MSG("MySQL connection failed: ~p~n"
"Waiting ~p seconds before retrying...~n",
[Reason, StartInterval div 1000]), [Reason, StartInterval div 1000]),
%% If we can't connect we wait before retrying %% If we can't connect we wait before retrying
timer:sleep(StartInterval), timer:sleep(StartInterval),

View File

@ -39,6 +39,11 @@
-define(DEFAULT_POOL_SIZE, 10). -define(DEFAULT_POOL_SIZE, 10).
-define(DEFAULT_ODBC_START_INTERVAL, 30). % 30 seconds -define(DEFAULT_ODBC_START_INTERVAL, 30). % 30 seconds
% time to wait for the supervisor to start its child before returning
% a timeout error to the request
-define(CONNECT_TIMEOUT, 500). % milliseconds
start_link(Host) -> start_link(Host) ->
supervisor:start_link({local, gen_mod:get_module_proc(Host, ?MODULE)}, supervisor:start_link({local, gen_mod:get_module_proc(Host, ?MODULE)},
?MODULE, [Host]). ?MODULE, [Host]).
@ -50,19 +55,23 @@ init([Host]) ->
undefined -> undefined ->
?DEFAULT_POOL_SIZE; ?DEFAULT_POOL_SIZE;
Other -> Other ->
?ERROR_MSG("Wrong odbc_pool_size definition '~p' for host ~p, default to ~p~n", ?ERROR_MSG("Wrong odbc_pool_size definition '~p' "
"for host ~p, default to ~p~n",
[Other, Host, ?DEFAULT_POOL_SIZE]), [Other, Host, ?DEFAULT_POOL_SIZE]),
?DEFAULT_POOL_SIZE ?DEFAULT_POOL_SIZE
end, end,
StartInterval = case ejabberd_config:get_local_option({odbc_start_interval, Host}) of StartInterval = case ejabberd_config:get_local_option({odbc_start_interval,
Host}) of
Interval when is_integer(Interval) -> Interval when is_integer(Interval) ->
Interval; Interval;
undefined -> undefined ->
?DEFAULT_ODBC_START_INTERVAL; ?DEFAULT_ODBC_START_INTERVAL;
_Other2 -> _Other2 ->
?ERROR_MSG("Wrong odbc_start_interval definition '~p' for host ~p" ?ERROR_MSG("Wrong odbc_start_interval "
", defaulting to ~p~n", "definition '~p' for host ~p, "
[_Other2, Host, ?DEFAULT_ODBC_START_INTERVAL]), "defaulting to ~p~n",
[_Other2, Host,
?DEFAULT_ODBC_START_INTERVAL]),
?DEFAULT_ODBC_START_INTERVAL ?DEFAULT_ODBC_START_INTERVAL
end, end,
{ok, {{one_for_one, PoolSize+1, StartInterval}, {ok, {{one_for_one, PoolSize+1, StartInterval},
@ -78,6 +87,11 @@ init([Host]) ->
get_pids(Host) -> get_pids(Host) ->
Proc = gen_mod:get_module_proc(Host, ?MODULE), Proc = gen_mod:get_module_proc(Host, ?MODULE),
% throw an exception if supervisor is not ready (i.e. if it cannot
% start its children, if the database is down for example)
sys:get_status(Proc, ?CONNECT_TIMEOUT),
[Child || [Child ||
{_Id, Child, _Type, _Modules} <- supervisor:which_children(Proc), {_Id, Child, _Type, _Modules} <- supervisor:which_children(Proc),
Child /= undefined]. Child /= undefined].