[99s-extend] Cowboy handler linked processes

Loïc Hoguin essen at ninenines.eu
Thu Jul 18 12:36:04 CEST 2013


I don't think the problem is that the handler is reused, we don't reuse 
them if there's an error. However we do catch errors to print them in 
the logs, and then the process stops normally. If you link without 
trap_exit you receive a normal exit signal which is ignored and doesn't 
kill your process. I suppose we should throw an exit signal when we got 
an error, after logging everything, instead of stopping normally.

On 07/18/2013 12:31 PM, Adrian Roe wrote:
> My issue is the other way round.  My handler crashes - and terminate
> gets called, but the linked process is NOT stopped (unless I stop it in
> terminate having stashed any processes I need to stop in the process
> dictionary - this is what I'm currently doing, but yuck!)
>
> .  My question is whether it wouldn't be better to no re-use the handler
> process that has crashed and replace it so that handler's can use the
> canonical erlang way of stopping related processes rather than having to
> do it by hand.
>
> Obviously if the handler does not crash there's no need to kill the
> process, so the current efficiency saving works in the "normal" case/
>
> --
> Dr Adrian Roe
> Director
>
> On Thursday, 18 July 2013 at 11:20, Loïc Hoguin wrote:
>
>> I don't know what happens but there's two things I know:
>>
>> * Handlers don't trap_exit, so if the linked process crashes, they
>> crash too
>> * If the handler crashes, we close the connection and stop the
>> handler; if not this is a bug
>>
>> After your log message the handler should stop unless there's a bug
>> somewhere.
>>
>> On 07/18/2013 12:15 PM, Adrian Roe wrote:
>>> We have been using spawn_linked workers to handle tasks that live for
>>> the lifetime of a single HTTP request
>>>
>>> Although in the cowboy guide it is clear that Cowboy can use "One
>>> Process of Many Requests" I am surprised that this is the case even if
>>> the handler crashes. For example, our use case is to copy a large file
>>> to the server over HTTP where a worker process relays the file contents
>>> to long term storage. The worker process is spawn_linked from the HTTP
>>> handler and (for our use case) should die if the handler stops.
>>>
>>> If the client stops the upload (for example by browsing away, or losing
>>> connectivity) we correctly receive an error (see sample Lager trace
>>> below), but what we are seeing is that spawn_linked processes are NOT
>>> being killed.
>>>
>>> Is this intended behaviour - I accept it makes sense to reuse the
>>> processes but should this continue to be the case even if the previous
>>> use of the process crashed? If it is intended behaviour I think the
>>> docs should highlight this as we've been leaking processes for some time
>>> now, but I've always seen it as erlang's job to look after related
>>> process trees in the event of error. Our current workaround is to hold
>>> a list of linked processes in process storage and then kill them in the
>>> terminate handler which is ugly in the extreme!! We don't know the PIDS
>>> of the linked processes until it is too late to return State to Cowboy
>>> (i.e. we are already in our handle code)...
>>>
>>> Kind regards
>>>
>>> Adrian
>>>
>>> 16:09:32.347 [info] Trailer upload failed with reason
>>> {case_clause,{error,closed}}
>>> 16:09:32.348 [error] ** Cowboy handler upload_trailer_resource
>>> terminating in handle/2
>>> for the reason error:{case_clause,{error,closed}}
>>> ** Handler state was {state,undefined,0,undefined,undefined,undefined}
>>> ** Request was
>>> [{socket,#Port<0.11230>},{transport,ranch_tcp},{connection,keepalive},{pid,<0.1987.0>},{method,<<"POST">>},{version,'HTTP/1.1'},{peer,{{84,92,32,116},64136}},{host,<<"54.225.117.108">>},{host_info,undefined},{port,8000},{path,<<"/upload_trailer">>},{path_info,undef
>>> ined},{qs,<<"name=linux-7.4.21.zip&size=54015414">>},{qs_vals,undefined},{bindings,[]},{headers,[{<<"host">>,<<"54.225.117.108:8000">>},{<<"connection">>,<<"keep-alive">>},{<<"content-length">>,<<"54015414">>},{<<"origin">>,<<"http://54.225.117.108:8000">>},{<<"user-agent">>,<<"M
>>> ozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML,
>>> like Gecko) Chrome/28.0.1500.71
>>> Safari/537.36">>},{<<"content-type">>,<<>>},{<<"accept">>,<<"*/*">>},{<<"referer">>,<<"http://54.225.117.108:8000/">>},{<<"accept-encoding">>,<<"gzip,deflate,sdch">>},{<<"acce
>>> pt-language">>,<<"en-US,en;q=0.8">>},{<<"cookie">>,<<"__jwpusr=cbc133d7-1b49-443c-8a13-364660cc93e5;
>>> id3as_manager=f4803c004d71dde3b64394f6e6f44faa54970e93">>}]},{p_headers,[{<<"connection">>,[<<"keep-alive">>]}]},{cookies,undefined},{meta,[]},{body_state,waiting},{multipart,unde
>>> fined},{buffer,<<>>},{resp_compress,true},{resp_state,waiting},{resp_headers,[]},{resp_body,<<>>},{onresponse,undefined}]
>>> ** Stacktrace:
>>> [{i_cowboy,stream_body,0,[{file,"src/i_cowboy.erl"},{line,76}]},{upload_trailer_resource,stream_upload_file,4,[{file,"src/endpoints/upload_trailer_resource.erl"},{line,247}]},{upload_trailer_resource,upload_file,1,[{file,"src/endpoints/upload_trailer_resource.erl"}
>>> ,{line,237}]},{upload_trailer_resource,head_or_post,1,[{file,"src/endpoints/upload_trailer_resource.erl"},{line,202}]},{upload_trailer_resource,sequence,2,[{file,"src/endpoints/upload_trailer_resource.erl"},{line,106}]},{upload_trailer_resource,process_request,1,[{file,"src/endpo
>>> ints/upload_trailer_resource.erl"},{line,212}]},{i_cowboy,do,3,[{file,"src/i_cowboy.erl"},{line,29}]},{cowboy_handler,handler_handle,4,[{file,"src/cowboy_handler.erl"},{line,119}]}]
>>>
>>>
>>> --
>>> Dr Adrian Roe
>>> Director
>>>
>>>
>>>
>>> _______________________________________________
>>> Extend mailing list
>>> Extend at lists.ninenines.eu <mailto:Extend at lists.ninenines.eu>
>>> http://lists.ninenines.eu:81/listinfo/extend
>>
>>
>> --
>> Loïc Hoguin
>> Erlang Cowboy
>> Nine Nines
>> http://ninenines.eu
>


-- 
Loïc Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu



More information about the Extend mailing list