mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-15 04:30:25 +00:00
Convert the documentation to Asciidoc
A few small revisions were made, and Erlang.mk has been updated.
This commit is contained in:
parent
b7d666cfc7
commit
4023e7f4e4
55 changed files with 5701 additions and 1889 deletions
146
doc/src/guide/loop_handlers.asciidoc
Normal file
146
doc/src/guide/loop_handlers.asciidoc
Normal file
|
@ -0,0 +1,146 @@
|
|||
[[loop_handlers]]
|
||||
== Loop handlers
|
||||
|
||||
Loop handlers are a special kind of HTTP handlers used when the
|
||||
response can not be sent right away. The handler enters instead
|
||||
a receive loop waiting for the right message before it can send
|
||||
a response.
|
||||
|
||||
Loop handlers are used for requests where a response might not
|
||||
be immediately available, but where you would like to keep the
|
||||
connection open for a while in case the response arrives. The
|
||||
most known example of such practice is known as long polling.
|
||||
|
||||
Loop handlers can also be used for requests where a response is
|
||||
partially available and you need to stream the response body
|
||||
while the connection is open. The most known example of such
|
||||
practice is known as server-sent events.
|
||||
|
||||
While the same can be accomplished using plain HTTP handlers,
|
||||
it is recommended to use loop handlers because they are well-tested
|
||||
and allow using built-in features like hibernation and timeouts.
|
||||
|
||||
Loop handlers essentially wait for one or more Erlang messages
|
||||
and feed these messages to the `info/3` callback. It also features
|
||||
the `init/2` and `terminate/3` callbacks which work the same as
|
||||
for plain HTTP handlers.
|
||||
|
||||
=== Initialization
|
||||
|
||||
The `init/2` function must return a `cowboy_loop` tuple to enable
|
||||
loop handler behavior. This tuple may optionally contain
|
||||
a timeout value and/or the atom `hibernate` to make the
|
||||
process enter hibernation until a message is received.
|
||||
|
||||
This snippet enables the loop handler.
|
||||
|
||||
[source,erlang]
|
||||
----
|
||||
init(Req, _Opts) ->
|
||||
{cowboy_loop, Req, #state{}}.
|
||||
----
|
||||
|
||||
However it is largely recommended that you set a timeout
|
||||
value. The next example sets a timeout value of 30s and
|
||||
also makes the process hibernate.
|
||||
|
||||
[source,erlang]
|
||||
----
|
||||
init(Req, _Opts) ->
|
||||
{cowboy_loop, Req, #state{}, 30000, hibernate}.
|
||||
----
|
||||
|
||||
=== Receive loop
|
||||
|
||||
Once initialized, Cowboy will wait for messages to arrive
|
||||
in the process' mailbox. When a message arrives, Cowboy
|
||||
calls the `info/3` function with the message, the Req object
|
||||
and the handler's state.
|
||||
|
||||
The following snippet sends a reply when it receives a
|
||||
`reply` message from another process, or waits for another
|
||||
message otherwise.
|
||||
|
||||
[source,erlang]
|
||||
----
|
||||
info({reply, Body}, Req, State) ->
|
||||
Req2 = cowboy_req:reply(200, [], Body, Req),
|
||||
{stop, Req2, State};
|
||||
info(_Msg, Req, State) ->
|
||||
{ok, Req, State, hibernate}.
|
||||
----
|
||||
|
||||
Do note that the `reply` tuple here may be any message
|
||||
and is simply an example.
|
||||
|
||||
This callback may perform any necessary operation including
|
||||
sending all or parts of a reply, and will subsequently
|
||||
return a tuple indicating if more messages are to be expected.
|
||||
|
||||
The callback may also choose to do nothing at all and just
|
||||
skip the message received.
|
||||
|
||||
If a reply is sent, then the `stop` tuple should be returned.
|
||||
This will instruct Cowboy to end the request.
|
||||
|
||||
Otherwise an `ok` tuple should be returned.
|
||||
|
||||
=== Streaming loop
|
||||
|
||||
Another common case well suited for loop handlers is
|
||||
streaming data received in the form of Erlang messages.
|
||||
This can be done by initiating a chunked reply in the
|
||||
`init/2` callback and then using `cowboy_req:chunk/2`
|
||||
every time a message is received.
|
||||
|
||||
The following snippet does exactly that. As you can see
|
||||
a chunk is sent every time a `chunk` message is received,
|
||||
and the loop is stopped by sending an `eof` message.
|
||||
|
||||
[source,erlang]
|
||||
----
|
||||
init(Req, _Opts) ->
|
||||
Req2 = cowboy_req:chunked_reply(200, [], Req),
|
||||
{cowboy_loop, Req2, #state{}}.
|
||||
|
||||
info(eof, Req, State) ->
|
||||
{stop, Req, State};
|
||||
info({chunk, Chunk}, Req, State) ->
|
||||
cowboy_req:chunk(Chunk, Req),
|
||||
{ok, Req, State};
|
||||
info(_Msg, Req, State) ->
|
||||
{ok, Req, State}.
|
||||
----
|
||||
|
||||
==== Cleaning up
|
||||
|
||||
It is recommended that you set the connection header to
|
||||
`close` when replying, as this process may be reused for
|
||||
a subsequent request.
|
||||
|
||||
Please refer to the xref:handlers[Handlers chapter]
|
||||
for general instructions about cleaning up.
|
||||
|
||||
=== Timeout
|
||||
|
||||
By default Cowboy will not attempt to close the connection
|
||||
if there is no activity from the client. This is not always
|
||||
desirable, which is why you can set a timeout. Cowboy will
|
||||
close the connection if no data was received from the client
|
||||
after the configured time. The timeout only needs to be set
|
||||
once and can't be modified afterwards.
|
||||
|
||||
Because the request may have had a body, or may be followed
|
||||
by another request, Cowboy is forced to buffer all data it
|
||||
receives. This data may grow to become too large though,
|
||||
so there is a configurable limit for it. The default buffer
|
||||
size is of 5000 bytes, but it may be changed by setting the
|
||||
`loop_max_buffer` middleware environment value.
|
||||
|
||||
=== Hibernate
|
||||
|
||||
To save memory, you may hibernate the process in between
|
||||
messages received. This is done by returning the atom
|
||||
`hibernate` as part of the `loop` tuple callbacks normally
|
||||
return. Just add the atom at the end and Cowboy will hibernate
|
||||
accordingly.
|
Loading…
Add table
Add a link
Reference in a new issue