-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
gracefully close connection fixes: #448 #487
base: main
Are you sure you want to change the base?
Conversation
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.
How about doing something like this instead:
// Shutdown sends a close message to the peer, waits for the peer to complete
// the closing handshake and closes the connection. Shutdown assumes that the
// application is reading the connection in another goroutine.
func (c *Conn) Shutdown(closeCode int, closeMessage string, timeout time.Duration) error {
// check for proper code and message
message := FormatCloseMessage(closeCode, closeMessage)
c.WriteControl(CloseMessage, message, time.Now().Add(writeWait)) // ignore error
select {
case <- time.After(timeout):
case <- c.done:
}
return c.Close()
}
The done field is a channel that's closed on receipt of a close message.
Accommodated comments @stevenscott89
So the question remains is, how do we detect if there is no reader and try to read close frame. And do we want to do this? RFC says after receiving CLOSE an endpoint shall close connection. But if we don't try to read and there is no reader also, we violate this and close conn only on timeout. |
The new channel field should be grouped with other read related fields and should be closed when c.readErr transitions from nil to non-nil. A function should be added for setting c.readErr instead of sprinkling the logic throughout the code. It's impossible to detect if the application is reading the connection or not. I think the application must specify this when calling shutdown. The API is getting cumbersome with yet another argument to shutdown. |
I agree, approaches would be debatable. Do you think this can be merged now and can later be matured when we discover more suitable ways to get it closer to RFC? |
I left comments in #448. The PR is not ready for merge:
This PR may need to wait for a new project maintainer to review. |
thanks @garyburd for suggestions. I had some ideas implemented on my dev setup to detect a read end (similar to |
Would this achieve a graceful shutdown? https://gist.github.com/feliperyan/2160d6df63f502079d7995372bc09e5c |
@feliperyan unless I'm crazy that gist will block in at least some cases because you are never receiving on the |
@IngCr3at1on Joining channel receives in the manageConns func. What im not certain about is: let’s say there’s 1000 clients and as I start iterating through them all, closing connections more and more new clients keep joining? I might never get to zero! How can I stop accepting new connections then start closing the existing connections? |
@feliperyan Yes, the program gracefully closes the connections. You may want to shutdown the server before waiting for the connections to close. Your question is not on the topic of this PR. Please open a new issue if you want to continue discussion about your program. |
its been some time. have we found new maintainer by any chance? |
Bunch of discussion on a very similar feature request in my library. coder/websocket#103 You might find it useful. |
I'm assigning myself to this PR, it may take some time to get familiar with the problem space and understand it to make a decision. If you feel that this PR is superseded by another or no longer relevant please reach out. |
@jaitaiwan when can we expect this to be merged? |
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.
LGTM, however I'd like either @apoorvajagtap or @AlexVulaj to review before a final final merge. From what I understand of the problem space it's okay to merge but it's a complex issue so just making sure that merging is the right move.
Please let's make sure concerns mentioned by Gary Burd in #487 (comment) and #448 (comment) are taken into account in this PR. @jaitaiwan do I understand correctly you investigated this before approving, right? |
Yep I've seen those. So far as I can tell, there's two arguments here:
It doesn't look like this PR changes any existing API interfaces, but it does add more - of which I don't see any issues with supporting especially considering it's a part of the RFC spec. I'll hold on this and await more feedback |
@@ -331,6 +332,28 @@ func (c *Conn) Close() error { | |||
return c.conn.Close() | |||
} | |||
|
|||
|
|||
// Shutdown sends a close frame to the peer and waits for close frame in resopnse. |
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.
// Shutdown sends a close frame to the peer and waits for close frame in resopnse. | |
// Shutdown sends a close frame to the peer and waits for close frame in response. |
I'm inclined to go with this option unless there's a strong reason not to, as this change seems a bit controversial. |
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.
This PR does not provide a way for the the read goroutine to gracefully execute the closing handshake.
There is a way implement graceful shutdown without the pitfalls described in my comments and others.
|
||
// Shutdown sends a close frame to the peer and waits for close frame in resopnse. | ||
// Shutdown assumes that the application is reading the connection in another | ||
// goroutine and hence it does not try to read close frame itself |
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.
The wording is not strong enough here. The documentation should say "The application must not call Shutdown from the reading goroutine."
Creating PR to request and accommodate comments. There are multiple areas which requires decision making.
wstest
?<- suggestions