mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-14 20:30:23 +00:00
Anonymize and improve the cowboy supervision tree.
* Cowboy isn't an OTP application anymore; just a supervisor. * All processes started by Cowboy are now anonymous. * All processes related to a listener are now part of its supervision tree.
This commit is contained in:
parent
e6e5b1767f
commit
e4da6956fc
7 changed files with 78 additions and 86 deletions
24
README.md
24
README.md
|
@ -33,21 +33,28 @@ Embedding Cowboy
|
||||||
Getting Started
|
Getting Started
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
Cowboy can be started and stopped like any other application. However the
|
Cowboy provides an anonymous listener supervisor that you can directly embed
|
||||||
Cowboy application do not start any listener, those must be started manually.
|
in your application's supervision tree.
|
||||||
|
|
||||||
A listener is a special kind of supervisor that handles a pool of acceptor
|
A listener is a special kind of supervisor that handles a pool of acceptor
|
||||||
processes. An acceptor simply accept connections and forward them to a
|
processes. It also manages all its associated request processes. This allows
|
||||||
protocol module, for example HTTP. You must thus define the transport and
|
you to shutdown all processes related to a listener by stopping the supervisor.
|
||||||
protocol module to use for the listener, their options and the number of
|
|
||||||
acceptors in the pool before you can start a listener supervisor.
|
An acceptor simply accepts connections and forwards them to a protocol module,
|
||||||
|
for example HTTP. You must thus define the transport and protocol module to
|
||||||
|
use for the listener, their options and the number of acceptors in the pool
|
||||||
|
before you can start a listener supervisor.
|
||||||
|
|
||||||
For HTTP applications the transport can be either TCP or SSL for HTTP and
|
For HTTP applications the transport can be either TCP or SSL for HTTP and
|
||||||
HTTPS respectively. On the other hand, the protocol is of course HTTP.
|
HTTPS respectively. On the other hand, the protocol is of course HTTP.
|
||||||
|
|
||||||
Code speaks more than words:
|
Code speaks more than words:
|
||||||
|
|
||||||
application:start(cowboy),
|
-module(my_app).
|
||||||
|
-behaviour(application).
|
||||||
|
-export([start/2, stop/1]).
|
||||||
|
|
||||||
|
start(_Type, _Args) ->
|
||||||
Dispatch = [
|
Dispatch = [
|
||||||
%% {Host, list({Path, Handler, Opts})}
|
%% {Host, list({Path, Handler, Opts})}
|
||||||
{'_', [{'_', my_handler, []}]}
|
{'_', [{'_', my_handler, []}]}
|
||||||
|
@ -58,6 +65,9 @@ Code speaks more than words:
|
||||||
cowboy_http_protocol, [{dispatch, Dispatch}]
|
cowboy_http_protocol, [{dispatch, Dispatch}]
|
||||||
).
|
).
|
||||||
|
|
||||||
|
stop(_State) ->
|
||||||
|
ok.
|
||||||
|
|
||||||
You must also write the `my_handler` module to process requests. You can
|
You must also write the `my_handler` module to process requests. You can
|
||||||
use one of the predefined handlers or write your own. An hello world HTTP
|
use one of the predefined handlers or write your own. An hello world HTTP
|
||||||
handler could be written like this:
|
handler could be written like this:
|
||||||
|
|
|
@ -20,7 +20,5 @@
|
||||||
{applications, [
|
{applications, [
|
||||||
kernel,
|
kernel,
|
||||||
stdlib
|
stdlib
|
||||||
]},
|
]}
|
||||||
{mod, {cowboy_app, []}},
|
|
||||||
{env, []}
|
|
||||||
]}.
|
]}.
|
||||||
|
|
|
@ -13,27 +13,28 @@
|
||||||
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
-module(cowboy_acceptor).
|
-module(cowboy_acceptor).
|
||||||
-export([start_link/4]). %% API.
|
-export([start_link/5]). %% API.
|
||||||
-export([acceptor/4]). %% Internal.
|
-export([acceptor/5]). %% Internal.
|
||||||
|
|
||||||
-include("include/types.hrl").
|
-include("include/types.hrl").
|
||||||
|
|
||||||
%% API.
|
%% API.
|
||||||
|
|
||||||
-spec start_link(LSocket::socket(), Transport::module(),
|
-spec start_link(LSocket::socket(), Transport::module(),
|
||||||
Protocol::module(), Opts::term()) -> {ok, Pid::pid()}.
|
Protocol::module(), Opts::term(), ReqsSup::pid()) -> {ok, Pid::pid()}.
|
||||||
start_link(LSocket, Transport, Protocol, Opts) ->
|
start_link(LSocket, Transport, Protocol, Opts, ReqsSup) ->
|
||||||
Pid = spawn_link(?MODULE, acceptor, [LSocket, Transport, Protocol, Opts]),
|
Pid = spawn_link(?MODULE, acceptor,
|
||||||
|
[LSocket, Transport, Protocol, Opts, ReqsSup]),
|
||||||
{ok, Pid}.
|
{ok, Pid}.
|
||||||
|
|
||||||
%% Internal.
|
%% Internal.
|
||||||
|
|
||||||
-spec acceptor(LSocket::socket(), Transport::module(),
|
-spec acceptor(LSocket::socket(), Transport::module(),
|
||||||
Protocol::module(), Opts::term()) -> no_return().
|
Protocol::module(), Opts::term(), ReqsSup::pid()) -> no_return().
|
||||||
acceptor(LSocket, Transport, Protocol, Opts) ->
|
acceptor(LSocket, Transport, Protocol, Opts, ReqsSup) ->
|
||||||
case Transport:accept(LSocket) of
|
case Transport:accept(LSocket) of
|
||||||
{ok, CSocket} ->
|
{ok, CSocket} ->
|
||||||
{ok, Pid} = supervisor:start_child(cowboy_protocols_sup,
|
{ok, Pid} = supervisor:start_child(ReqsSup,
|
||||||
[CSocket, Transport, Protocol, Opts]),
|
[CSocket, Transport, Protocol, Opts]),
|
||||||
Transport:controlling_process(CSocket, Pid);
|
Transport:controlling_process(CSocket, Pid);
|
||||||
{error, _Reason} ->
|
{error, _Reason} ->
|
||||||
|
@ -41,4 +42,4 @@ acceptor(LSocket, Transport, Protocol, Opts) ->
|
||||||
%% we may want to try and listen again on the port?
|
%% we may want to try and listen again on the port?
|
||||||
ignore
|
ignore
|
||||||
end,
|
end,
|
||||||
?MODULE:acceptor(LSocket, Transport, Protocol, Opts).
|
?MODULE:acceptor(LSocket, Transport, Protocol, Opts, ReqsSup).
|
||||||
|
|
|
@ -12,26 +12,29 @@
|
||||||
%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
-module(cowboy_sup).
|
-module(cowboy_acceptors_sup).
|
||||||
-behaviour(supervisor).
|
-behaviour(supervisor).
|
||||||
|
|
||||||
-export([start_link/0]). %% API.
|
-export([start_link/6]). %% API.
|
||||||
-export([init/1]). %% supervisor.
|
-export([init/1]). %% supervisor.
|
||||||
|
|
||||||
-define(SUPERVISOR, ?MODULE).
|
-include("include/types.hrl").
|
||||||
|
|
||||||
%% API.
|
%% API.
|
||||||
|
|
||||||
-spec start_link() -> {ok, Pid::pid()}.
|
-spec start_link(NbAcceptors::non_neg_integer(), Transport::module(),
|
||||||
start_link() ->
|
TransOpts::term(), Protocol::module(), ProtoOpts::term(), ReqsPid::pid())
|
||||||
supervisor:start_link({local, ?SUPERVISOR}, ?MODULE, []).
|
-> {ok, Pid::pid()}.
|
||||||
|
start_link(LSocket, NbAcceptors, Transport, Protocol, ProtoOpts, ReqsPid) ->
|
||||||
|
supervisor:start_link(?MODULE, [LSocket, NbAcceptors,
|
||||||
|
Transport, Protocol, ProtoOpts, ReqsPid]).
|
||||||
|
|
||||||
%% supervisor.
|
%% supervisor.
|
||||||
|
|
||||||
-spec init([]) -> term(). %% @todo These specs should be improved.
|
-spec init(list(term())) -> term(). %% @todo These specs should be improved.
|
||||||
init([]) ->
|
init([LSocket, NbAcceptors, Transport, Protocol, ProtoOpts, ReqsPid]) ->
|
||||||
Procs = [
|
Procs = [{{acceptor, self(), N}, {cowboy_acceptor, start_link, [
|
||||||
{cowboy_protocols_sup, {cowboy_protocols_sup, start_link, []},
|
LSocket, Transport, Protocol, ProtoOpts, ReqsPid
|
||||||
permanent, 5000, supervisor, [cowboy_protocols_sup]}
|
]}, permanent, brutal_kill, worker, dynamic}
|
||||||
],
|
|| N <- lists:seq(1, NbAcceptors)],
|
||||||
{ok, {{one_for_one, 10, 10}, Procs}}.
|
{ok, {{one_for_one, 10, 10}, Procs}}.
|
|
@ -1,30 +0,0 @@
|
||||||
%% Copyright (c) 2011, Loïc Hoguin <essen@dev-extend.eu>
|
|
||||||
%%
|
|
||||||
%% Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
%% purpose with or without fee is hereby granted, provided that the above
|
|
||||||
%% copyright notice and this permission notice appear in all copies.
|
|
||||||
%%
|
|
||||||
%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
|
|
||||||
-module(cowboy_app).
|
|
||||||
-behaviour(application).
|
|
||||||
|
|
||||||
-export([start/2, stop/1]). %% API.
|
|
||||||
|
|
||||||
-include("include/types.hrl").
|
|
||||||
|
|
||||||
%% API.
|
|
||||||
|
|
||||||
-spec start(Type::application_start_type(), Args::term()) -> {ok, Pid::pid()}.
|
|
||||||
start(_Type, _Args) ->
|
|
||||||
cowboy_sup:start_link().
|
|
||||||
|
|
||||||
-spec stop(State::term()) -> ok.
|
|
||||||
stop(_State) ->
|
|
||||||
ok.
|
|
|
@ -26,8 +26,7 @@
|
||||||
start_link(NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts) ->
|
start_link(NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts) ->
|
||||||
case Transport:listen(TransOpts) of
|
case Transport:listen(TransOpts) of
|
||||||
{ok, LSocket} ->
|
{ok, LSocket} ->
|
||||||
supervisor:start_link(?MODULE, [LSocket,
|
start_sup(LSocket, NbAcceptors, Transport, Protocol, ProtoOpts);
|
||||||
NbAcceptors, Transport, Protocol, ProtoOpts]);
|
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
end.
|
end.
|
||||||
|
@ -35,9 +34,22 @@ start_link(NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts) ->
|
||||||
%% supervisor.
|
%% supervisor.
|
||||||
|
|
||||||
%% @todo These specs should be improved.
|
%% @todo These specs should be improved.
|
||||||
-spec init(list(term())) -> term().
|
-spec init([]) -> term().
|
||||||
init([LSocket, NbAcceptors, Transport, Protocol, ProtoOpts]) ->
|
init([]) ->
|
||||||
Procs = [{{acceptor, self(), N}, {cowboy_acceptor, start_link,
|
{ok, {{one_for_one, 0, 1}, []}}.
|
||||||
[LSocket, Transport, Protocol, ProtoOpts]}, permanent,
|
|
||||||
brutal_kill, worker, dynamic} || N <- lists:seq(1, NbAcceptors)],
|
%% Internal.
|
||||||
{ok, {{one_for_one, 10, 10}, Procs}}.
|
|
||||||
|
-spec start_sup(NbAcceptors::non_neg_integer(), Transport::module(),
|
||||||
|
TransOpts::term(), Protocol::module(), ProtoOpts::term())
|
||||||
|
-> {ok, Pid::pid()}.
|
||||||
|
start_sup(LSocket, NbAcceptors, Transport, Protocol, ProtoOpts) ->
|
||||||
|
{ok, SupPid} = supervisor:start_link(?MODULE, []),
|
||||||
|
{ok, ReqsPid} = supervisor:start_child(SupPid,
|
||||||
|
{cowboy_requests_sup, {cowboy_requests_sup, start_link, []},
|
||||||
|
permanent, 5000, supervisor, [cowboy_requests_sup]}),
|
||||||
|
{ok, _PoolPid} = supervisor:start_child(SupPid,
|
||||||
|
{cowboy_acceptors_sup, {cowboy_acceptors_sup, start_link, [
|
||||||
|
LSocket, NbAcceptors, Transport, Protocol, ProtoOpts, ReqsPid
|
||||||
|
]}, permanent, 5000, supervisor, [cowboy_acceptors_sup]}),
|
||||||
|
{ok, SupPid}.
|
||||||
|
|
|
@ -12,30 +12,28 @@
|
||||||
%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
-module(cowboy_protocols_sup).
|
-module(cowboy_requests_sup).
|
||||||
-behaviour(supervisor).
|
-behaviour(supervisor).
|
||||||
|
|
||||||
-export([start_link/0, start_protocol/4]). %% API.
|
-export([start_link/0, start_request/4]). %% API.
|
||||||
-export([init/1]). %% supervisor.
|
-export([init/1]). %% supervisor.
|
||||||
|
|
||||||
-include("include/types.hrl").
|
-include("include/types.hrl").
|
||||||
|
|
||||||
-define(SUPERVISOR, ?MODULE).
|
|
||||||
|
|
||||||
%% API.
|
%% API.
|
||||||
|
|
||||||
-spec start_link() -> {ok, Pid::pid()}.
|
-spec start_link() -> {ok, Pid::pid()}.
|
||||||
start_link() ->
|
start_link() ->
|
||||||
supervisor:start_link({local, ?SUPERVISOR}, ?MODULE, []).
|
supervisor:start_link(?MODULE, []).
|
||||||
|
|
||||||
-spec start_protocol(Socket::socket(), Transport::module(),
|
-spec start_request(Socket::socket(), Transport::module(),
|
||||||
Protocol::module(), Opts::term()) -> {ok, Pid::pid()}.
|
Protocol::module(), Opts::term()) -> {ok, Pid::pid()}.
|
||||||
start_protocol(Socket, Transport, Protocol, Opts) ->
|
start_request(Socket, Transport, Protocol, Opts) ->
|
||||||
Protocol:start_link(Socket, Transport, Opts).
|
Protocol:start_link(Socket, Transport, Opts).
|
||||||
|
|
||||||
%% supervisor.
|
%% supervisor.
|
||||||
|
|
||||||
-spec init([]) -> term(). %% @todo These specs should be improved.
|
-spec init([]) -> term(). %% @todo These specs should be improved.
|
||||||
init([]) ->
|
init([]) ->
|
||||||
{ok, {{simple_one_for_one, 0, 1}, [{?MODULE, {?MODULE, start_protocol, []},
|
{ok, {{simple_one_for_one, 0, 1}, [{?MODULE, {?MODULE, start_request, []},
|
||||||
temporary, brutal_kill, worker, [?MODULE]}]}}.
|
temporary, brutal_kill, worker, [?MODULE]}]}}.
|
Loading…
Add table
Add a link
Reference in a new issue