http:request hangs

Denis Titoruk <>
Thu Nov 19 15:24:40 CET 2009


Hi,
I am making asynchronous(keep-alive) http requests, sometimes requests  
hang.

Version: R13B02-1
OS: Max OS X 10.5.8
Test case:

#!/usr/local/bin/escript

-define(URL, "http://my_local_web_server/").

executeMultipleTimes(0, _) -> ok;
executeMultipleTimes(N, F) -> F(N), executeMultipleTimes(N-1, F).

executeMultipleTimes(0, _, _) -> ok;
executeMultipleTimes(N, F, P) -> F(P, N), executeMultipleTimes(N-1, F,  
P).

collectMessages(0, _) -> ok;
collectMessages(N, Msg) -> receive Msg -> collectMessages(N - 1, Msg)  
end.

parallel(Parallel, Cycles, F) ->
	Self = self(),
	Pid = spawn_link(fun() ->
			collectMessages(Parallel, finished),
			Self ! ready
		end),
	executeMultipleTimes(Parallel, fun(P) ->
			spawn_link(fun() ->
				executeMultipleTimes(Cycles, F, P),
				Pid ! finished
			end)
		end),
	receive ready -> ok end.

main(_) ->
	inets:start(),
	F = fun(P, C) ->
		io:format("starting ~p:~p~n",[P, C]),
		URL = ?URL ++ "#" ++ integer_to_list(P) ++
			":" ++ integer_to_list(C),
		R = http:request(get, {URL, []}, [], []),
		io:format("started ~p:~p~n",[P, C]),
		case R of
			{ok, _} -> ok;
			_ -> io:format("error ~p:~p = [~p]~n",[P, C, R])
		end
	end,
	parallel(4, 250, F).

--------------
Possible patch:
This patch appears to be working in my test case, but I am not sure it  
solves the issue completely. Please take a look at yourselves.

httpc_handler.erl
287c287
<           return_error(pipline_failed, Reason, State)
---
 >           {reply, {pipline_failed, Reason}, State}
340c340
<           return_error(request_failed, Reason, State)
---
 >           {reply, {request_failed, Reason}, State}
343,350d342
< return_error(Error, Reason, State) ->
<     Queue = case State#state.status of
<       pipeline -> State#state.pipeline;
<       keep_alive -> State#state.keep_alive;
<       _ -> []
<     end,
<     {reply, {Error, Reason, [State#state.request |  
queue:to_list(Queue)]}, State#state{ pipeline = queue:new(),  
keep_alive = queue:new() }}.
<

httpc_manager.erl
366,370d365
<     Requests = ets:match(State#state.handler_db, {'$1', Pid, '$2'}),
<     [begin
<       httpc_response:send(From, {Id, {error, internal_error}}) end ||
<               [Id, From] <- Requests],
<
508,514c503
<       Error  -> %timeout pipelining failed
<           case Error of
<               {request_failed, _Reason, Queue} ->
<                       spawn(fun() -> restart_requests(Queue, State)  
end);
<               _E ->
<                       ok
<           end,
---
 >       _  -> %timeout pipelining failed
518,532d506
< restart_requests([], _) -> ok;
< restart_requests([undefined | Queue], State) ->
<     restart_requests(Queue, State);
< restart_requests([Request = #request{ from = answer_sent} | Queue],  
State) ->
<     restart_requests(Queue, State);
< restart_requests([Request | Queue], State) ->
<     restart_request(Request, State),
<     restart_requests(Queue, State).
<
< restart_request(Request, State) ->
<     ProfileName = State#state.profile_name,
<     catch ets:delete(State#state.handler_db, Request#request.id),
<     httpc_manager:request(Request, ProfileName).
<
<

As you can see, there are two issues
1. when you receive  {error, closed} in httpc_request:send & there are  
few requests in queue
2. when handler process died



More information about the erlang-bugs mailing list