Comments (5)
The problem occurs because cowboy_websocket
(or any ranch_protocol
) calls ranch_server:remove_connection/1
[1], which leads to ranch_conns_sup
reducing its current connection count[2]. However once the websocket (or any ranch_protocol
that removes connections) exits the connection count is reduced again[3] and so the count is 1 less than the actual count for every connection that has removed itself and then exited.
In order to handle this properly the state of each connection needs to be kept. Currently the pids of connection are stored in the process dictionary with pid keys and true
values. The value could be the state (e.g. current
or removed
) instead of true
. This can be set if the Pid
is added to the remove_connection
message (e.g. {remove_connection, Ref, self()}
):
case put(Pid, removed) of
current ->
loop(State, CurConns - 1, NbChildren, Sleepers);
% Already removed, buggy ranch_protocol. Currently decrement regardless!
removed ->
loop(State, CurConns, NbChildren, Sleepers);
% Bad message?! Currently decrement regardless!
undefined ->
erase(Pid),
loop(State, CurConns, NbChildren, Sleepers)
end
On a child's exit the Pid
is erased, which allows retrieval of its state:
case erase(Pid) of
current ->
report_error(Ref, Protocol, Pid, Reason),
loop(State, CurConns - 1, NbChildren -1, Sleepers);
% Already reduced the connection count for this child. Currently decrement regardless!
removed ->
report_error(Ref, Protocol, Pid, Reason),
loop(State, CurConns, NbChildren - 1, Sleepers);
% The exit signal is not from a child. Currently decremented regardless!
undefined ->
loop(State, CurConns, NbChildren, Sleepers)
end
This would also allow better behaviour when max_connections
has been reduced. Currently acceptors are slept once they accept a socket if max connections has been exceeded. However as soon as a child exits an acceptor is woken up without considering the current connection count and max connection limit. Therefore in the case where the max connection limit is reduced below the current connection count, the limit is not being obeyed. Instead the state of the exiting process can be used to only wake up acceptors when appropriate:
case erase(Pid) of
% Currently no check done for CurConns =< MaxConns when awakening an acceptor.
current when Sleepers =/= [] andalso CurConns =< MaxConns ->
report_error(Ref, Protocol, Pid, Reason),
[To|Sleepers2] = Sleepers,
To ! self(),
loop(State, CurConns - 1, NbChildren - 1, Sleepers2);
current ->
report_error(Ref, Protocol, Pid, Reason),
loop(State, CurConns - 1, NbChildren - 1, Sleepers);
removed ->
report_error(Ref, Protocol, Pid, Reason),
loop(State, CurConns, NbChildren - 1, Sleepers);
undefined ->
loop(State, CurConns, NbChildren, Sleepers)
end
Also note that the awaking of acceptors should be added to the remove_connection
clause. Currently this is not done and is a related bug:
case put(Pid, removed) of
current when Sleepers =/= [] andalso CurConns =< MaxConns ->
[To|Sleepers2] = Sleepers,
To ! self(),
loop(State, CurConns - 1, NbChildren, Sleepers2);
current ->
loop(State, CurConns - 1, NbChildren, Sleepers);
removed ->
loop(State, CurConns, NbChildren, Sleepers);
undefined ->
erase(Pid),
loop(State, CurConns, NbChildren, Sleepers)
end
Line 143 in a410985
[3]
Line 162 in a410985
Line 169 in a410985
from ranch.
I agree with everything you say here. Sounds like you're pretty far already so I'm guessing there'll be a PR coming. :-)
"removed" makes sense but I'm not sure what "current" means, what's the opposite of "removed"?
from ranch.
I'm not sure why I used current, I think because of the CurCons
(current connections) variable. The opposite of removed is added. I think included is better because the pid is included in the connection count.
Sure a PR can appear once I have time to add some tests.
from ranch.
"included" sounds good. Thanks in advance!
from ranch.
I am cherry-picking fishcakez@c3a3862 and adding a test. Test was very quick to write, and demonstrates that the issue is fixed. I also like active
more than current
or included
.
Closing, thanks!
from ranch.
Related Issues (20)
- Add more Concuerror tests
- How can gen_tcp be configured to support both IPv4 and IPv6 connections HOT 4
- Supervisor protocol process cannot be stopped when connection is closed (connection_type=supervisor). HOT 15
- Upgrading from 1.4 to 2.0 HOT 5
- Release Ranch 1.8 that is compatible with OTP-24 HOT 15
- Ranch 1.7, issues upgrading a tcp to ssl/tls connection HOT 7
- Add hex metadata to Ranch master HOT 1
- Add a function that converts from ProxyInfo to ssl:connection_information/1 return value HOT 2
- using gen_tcp new interface inet_backend socket cann't listen multiple sockets in one port HOT 6
- remove the socket file before the listen and change_mode the socket file right after listen HOT 14
- Update appup for 2.1.0 HOT 3
- Proxy protocol unique ID TLV type HOT 1
- The user guide links on the README are broken HOT 1
- Password should be blanked instead of logged on error HOT 1
- TLS 1.3 connection with client verification always successful HOT 1
- ranch:handshake(Ref) silently drops invalid TLS connections in ranch_ssl via exit(normal) HOT 16
- Questions about "gen_tcp:accept/2" and "num_acceptors" HOT 2
- ranch:stop_listener/1 throws error HOT 2
- {error, no_cert} with `certs_keys` from OTP 25 HOT 8
- Issue when using DTLS HOT 6
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ranch.