Browse Source

Get a new lb pid if existing pid is not alive

It's possible for the connection process associated with a pid in the
ibrowse_lb ets table to die, yet remain in the table, in which case
subsequent requests to the corresponding {Host, Port} will result in an
error like the following:

(node1@127.0.0.1)9> ibrowse:send_req("http://localhost:15984", [], get).
                ** exception exit: {noproc,
                       {gen_server,call,
                           [<0.2451.0>,
                            {spawn_connection,
                                {url,"http://localhost:15984","localhost",15984,
                                    undefined,undefined,"/",http,hostname},
                                10,10,
                                {[],false},
                                []}]}}
     in function  gen_server:call/2 (gen_server.erl, line 215)
     in call from ibrowse:try_routing_request/14 (src/ibrowse.erl, line 377)

This checks whether the pid about to be returned from the table is alive,
and if not, the entry is deleted, and a new pid is obtained.
pull/166/head
Jay Doane 6 years ago
parent
commit
313362c56b
2 changed files with 34 additions and 6 deletions
  1. +15
    -6
      src/ibrowse.erl
  2. +19
    -0
      test/ibrowse_test.erl

+ 15
- 6
src/ibrowse.erl View File

@ -342,12 +342,7 @@ send_req(Url, Headers, Method, Body, Options, Timeout) ->
#url{host = Host,
port = Port,
protocol = Protocol} = Parsed_url ->
Lb_pid = case ets:lookup(ibrowse_lb, {Host, Port}) of
[] ->
get_lb_pid(Parsed_url);
[#lb_pid{pid = Lb_pid_1}] ->
Lb_pid_1
end,
Lb_pid = lb_pid(Host, Port, Parsed_url),
Max_sessions = get_max_sessions(Host, Port, Options),
Max_pipeline_size = get_max_pipeline_size(Host, Port, Options),
Max_attempts = get_max_attempts(Host, Port, Options),
@ -367,6 +362,20 @@ send_req(Url, Headers, Method, Body, Options, Timeout) ->
{error, {url_parsing_failed, Err}}
end.
lb_pid(Host, Port, Url) ->
case ets:lookup(ibrowse_lb, {Host, Port}) of
[] ->
get_lb_pid(Url);
[#lb_pid{pid = Pid}] ->
case is_process_alive(Pid) of
true ->
Pid;
false ->
ets:delete(ibrowse_lb, {Host, Port}),
get_lb_pid(Url)
end
end.
try_routing_request(Lb_pid, Parsed_url,
Max_sessions,
Max_pipeline_size,

+ 19
- 0
test/ibrowse_test.erl View File

@ -34,6 +34,7 @@
test_preserve_status_line/0,
test_binary_headers/0,
test_binary_headers/1,
test_dead_lb_pid/0,
test_generate_body_0/0,
test_retry_of_requests/0,
test_retry_of_requests/1,
@ -61,6 +62,7 @@
{local_test_fun, test_303_response_with_a_body, []},
{local_test_fun, test_303_response_with_no_body, []},
{local_test_fun, test_binary_headers, []},
{local_test_fun, test_dead_lb_pid, []},
{local_test_fun, test_retry_of_requests, []},
{local_test_fun, verify_chunked_streaming, []},
{local_test_fun, test_chunked_streaming_once, []},
@ -877,6 +879,23 @@ test_generate_body_0() ->
ets:delete(Tid)
end.
%%------------------------------------------------------------------------------
%% Test that when an lb process dies, its entry is removed from the ibrowse_lb
%% table by the next requestor and replaced with a new process
%%------------------------------------------------------------------------------
test_dead_lb_pid() ->
{Host, Port} = {"localhost", 8181},
Url = "http://" ++ Host ++ ":" ++ integer_to_list(Port),
{ok, "200", _, _} = ibrowse:send_req(Url, [], get),
[{lb_pid, {Host, Port}, Pid, _}] = ets:lookup(ibrowse_lb, {Host, Port}),
true = exit(Pid, kill),
false = is_process_alive(Pid),
{ok, "200", _, _} = ibrowse:send_req(Url, [], get),
[{lb_pid, {Host, Port}, NewPid, _}] = ets:lookup(ibrowse_lb, {Host, Port}),
true = NewPid /= Pid,
true = is_process_alive(NewPid),
success.
do_trace(Fmt, Args) ->
do_trace(get(my_trace_flag), Fmt, Args).

Loading…
Cancel
Save