-
Notifications
You must be signed in to change notification settings - Fork 183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ConnectionPool: monitor idle connections #236
Conversation
When a connection is returned to the (read) pool, add a monitor to it for receiving unexpected data (or EOF), and kill / close the Connection object if any activity occurs before the next write (when it should have simply been waiting idle in the pool) per JuliaLang/MbedTLS.jl#145 (comment) closes #214 closes #199 closes #220 closes JuliaWeb/GitHub.jl#106
From JuliaWeb/GitHub.jl#106 (comment):
The change in this PR, or #235, and |
I haven't yet reviewed that the busy/count/sequence logic is correct, but I get the point. We want to say "if we are not expecting data". Compared to #235:
For the purposes of arbitrary local pedantry, I would:
|
This might be better, i.e. if the connection is EOF (nothing more to read), then close it (signal won't write any more). --- a/src/ConnectionPool.jl
+++ b/src/ConnectionPool.jl
@@ -270,7 +270,7 @@ function IOExtras.closeread(t::Transaction)
# short-circuit if it is already dead or has already started to be reused
if isopen(t.c) && !t.c.writebusy && (t.c.writecount <= t.sequence + 1) # && !isreadable(t)
@schedule begin
- if !eof(t.c.io) && # wait to see if receive any more data
+ if eof(t.c.io) || # wait to see if receive any more data
!t.c.readbusy && # and aren't actively expecting to receive data
!t.c.writebusy && (t.c.writecount <= t.sequence + 1) # nor have returned from startwrite and/or called closewrite again
# other end must be in an invalid state, or terminated the connection: |
…tion. - Move close() on eof() || !isbusy() to new monitor_idle_connection function. - Make monitor_idle_connection() a noop for ::Connection{SSLContext}
Hi @vtjnash, @quinnj,
Please review, and please excuse me if I've blatted an important detail in my reinterpretation. |
Lgtm. I was assuming that seeing |
@@ -264,10 +270,32 @@ function IOExtras.closeread(t::Transaction) | |||
notify(t.c.readdone) ;@debug 2 "✉️ Read done: $t" | |||
notify(poolcondition) | |||
|
|||
if !isbusy(t.c) | |||
@schedule monitor_idle_connection(t.c) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe worth doing let c = t.c; @schedule monitor_idle_connection(t.c); end
, so we don't capture all of t
. But afaik, there's no finalizers
on t
, or other way to see this difference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, t
is an immutable struct containing just c
and an Int
, so probably not much difference.
But it's a good reminder to consider what is being captured in closures. I have a feeling I should be more cognisant of that more often...
AFAICT |
Doesn't usually matter, unless you think it's going to be long-lived relative to the object that it wraps and holds lots of other references too.
Makes sense. Seems like you're really great at finding bugs, though :) |
We need to make a fundamental decision:
If we go for model A) we can still have convenience methods to hide read vs write (e.g. Going for model B) might not be unreasonable. We could argue that protocols that rely on In model B), calling The current situation feels like it is somewhere in between, we mostly try to hide the distinction between the send and receive sides of the connection, but then we have Either way, I think we need a section under Interfaces that lays down the law and a state diagram that shows what sequences of state transitions is allowed and what causes them. |
@vtjnash, is this that? https://travis-ci.org/JuliaWeb/HTTP.jl/jobs/368429787#L4837-L4842
|
SHUT_RDWR is a bit different, since it affects the file description, not the file descriptor. I think model A would be more consistent, especially with things like Yep, that's the manifestation of that bug. |
FWIW, I saw the |
This PR I think is a no-op for HTTPS workloads |
WIP notes...
|
@samoconnor, @vtjnash, should we merge this now that the IdDict bug is fixed in julia master? |
I would prefer to wait until there is a Julia 0.6.3 with the IdDict bugfix and/or put an |
@vtjnash, what do you think about the status of this PR? can we put versioning so it only applies to 0.7 w/ the idDict bug fixed? |
Codecov Report
@@ Coverage Diff @@
## master #236 +/- ##
==========================================
+ Coverage 71.52% 71.59% +0.06%
==========================================
Files 35 35
Lines 1886 1894 +8
==========================================
+ Hits 1349 1356 +7
- Misses 537 538 +1
Continue to review full report at Codecov.
|
@quinnj, I've just pushed a commit to this PR to require 0.6.3. |
I'm seeing tests hang on 0.6 on CI: https://travis-ci.org/JuliaWeb/HTTP.jl/jobs/386029926, https://ci.appveyor.com/project/quinnj/http-jl/build/1.0.611/job/u7y9uj2m3ol6neau. @samoconnor, @vtjnash, could there be something in the changes here that would cause 0.6 to hang? |
@samoconnor, I can reproduce the hang locally on 0.6; it seems to hang on this block: https://github.com/JuliaWeb/HTTP.jl/blob/master/test/loopback.jl#L203. Could you take a look? |
Ok, this was actually a conflict of sorts w/ my 0.7 compat PR, which changed |
When a connection is returned to the (read) pool,
add a monitor to it for receiving unexpected data (or EOF),
and kill / close the Connection object if any activity occurs
before the next write (when it should have simply been waiting idle in the pool)
per JuliaLang/MbedTLS.jl#145 (comment)
closes #214
closes #199
closes #220
closes JuliaWeb/GitHub.jl#106
replaces #235