mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-14 12:20:24 +00:00
Add a max_connections transport option.
Limits the number of parallel requests processed at once. Waiting requests are kept in the accept queue. The limit is not explicitly observed, but it should be around the given value at any time. Defaults to 1024. Thanks to ostinelli's benchmark to point out the issue hopefully solved by this and the previous commit.
This commit is contained in:
parent
b3d3045cae
commit
5d698250b2
2 changed files with 23 additions and 10 deletions
|
@ -13,28 +13,31 @@
|
||||||
%% 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/5]). %% API.
|
-export([start_link/6]). %% API.
|
||||||
-export([acceptor/5]). %% Internal.
|
-export([acceptor/6]). %% Internal.
|
||||||
|
|
||||||
%% API.
|
%% API.
|
||||||
|
|
||||||
-spec start_link(LSocket::inet:socket(), Transport::module(),
|
-spec start_link(LSocket::inet:socket(), Transport::module(),
|
||||||
Protocol::module(), Opts::term(), ReqsSup::pid()) -> {ok, Pid::pid()}.
|
Protocol::module(), Opts::term(),
|
||||||
start_link(LSocket, Transport, Protocol, Opts, ReqsSup) ->
|
MaxConns::non_neg_integer(), ReqsSup::pid()) -> {ok, Pid::pid()}.
|
||||||
|
start_link(LSocket, Transport, Protocol, Opts, MaxConns, ReqsSup) ->
|
||||||
Pid = spawn_link(?MODULE, acceptor,
|
Pid = spawn_link(?MODULE, acceptor,
|
||||||
[LSocket, Transport, Protocol, Opts, ReqsSup]),
|
[LSocket, Transport, Protocol, Opts, MaxConns, ReqsSup]),
|
||||||
{ok, Pid}.
|
{ok, Pid}.
|
||||||
|
|
||||||
%% Internal.
|
%% Internal.
|
||||||
|
|
||||||
-spec acceptor(LSocket::inet:socket(), Transport::module(),
|
-spec acceptor(LSocket::inet:socket(), Transport::module(),
|
||||||
Protocol::module(), Opts::term(), ReqsSup::pid()) -> no_return().
|
Protocol::module(), Opts::term(),
|
||||||
acceptor(LSocket, Transport, Protocol, Opts, ReqsSup) ->
|
MaxConns::non_neg_integer(), ReqsSup::pid()) -> no_return().
|
||||||
|
acceptor(LSocket, Transport, Protocol, Opts, MaxConns, ReqsSup) ->
|
||||||
case Transport:accept(LSocket, 2000) of
|
case Transport:accept(LSocket, 2000) of
|
||||||
{ok, CSocket} ->
|
{ok, CSocket} ->
|
||||||
{ok, Pid} = supervisor:start_child(ReqsSup,
|
{ok, Pid} = supervisor:start_child(ReqsSup,
|
||||||
[CSocket, Transport, Protocol, Opts]),
|
[CSocket, Transport, Protocol, Opts]),
|
||||||
Transport:controlling_process(CSocket, Pid);
|
Transport:controlling_process(CSocket, Pid),
|
||||||
|
limit_reqs(MaxConns, ReqsSup);
|
||||||
{error, timeout} ->
|
{error, timeout} ->
|
||||||
ignore;
|
ignore;
|
||||||
{error, _Reason} ->
|
{error, _Reason} ->
|
||||||
|
@ -42,4 +45,13 @@ acceptor(LSocket, Transport, Protocol, Opts, ReqsSup) ->
|
||||||
%% 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, ReqsSup).
|
?MODULE:acceptor(LSocket, Transport, Protocol, Opts, MaxConns, ReqsSup).
|
||||||
|
|
||||||
|
-spec limit_reqs(MaxConns::non_neg_integer(), ReqsSup::pid()) -> ok.
|
||||||
|
limit_reqs(MaxConns, ReqsSup) ->
|
||||||
|
Counts = supervisor:count_children(ReqsSup),
|
||||||
|
Active = lists:keyfind(active, 1, Counts),
|
||||||
|
case Active < MaxConns of
|
||||||
|
true -> ok;
|
||||||
|
false -> timer:sleep(1)
|
||||||
|
end.
|
||||||
|
|
|
@ -32,8 +32,9 @@ start_link(NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts, ReqsPid) ->
|
||||||
-spec init(list(term())) -> term(). %% @todo These specs should be improved.
|
-spec init(list(term())) -> term(). %% @todo These specs should be improved.
|
||||||
init([NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts, ReqsPid]) ->
|
init([NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts, ReqsPid]) ->
|
||||||
{ok, LSocket} = Transport:listen(TransOpts),
|
{ok, LSocket} = Transport:listen(TransOpts),
|
||||||
|
MaxConns = proplists:get_value(max_connections, TransOpts, 1024),
|
||||||
Procs = [{{acceptor, self(), N}, {cowboy_acceptor, start_link, [
|
Procs = [{{acceptor, self(), N}, {cowboy_acceptor, start_link, [
|
||||||
LSocket, Transport, Protocol, ProtoOpts, ReqsPid
|
LSocket, Transport, Protocol, ProtoOpts, MaxConns, ReqsPid
|
||||||
]}, permanent, brutal_kill, worker, dynamic}
|
]}, permanent, brutal_kill, worker, dynamic}
|
||||||
|| N <- lists:seq(1, NbAcceptors)],
|
|| N <- lists:seq(1, NbAcceptors)],
|
||||||
{ok, {{one_for_one, 10, 10}, Procs}}.
|
{ok, {{one_for_one, 10, 10}, Procs}}.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue