Skip to content

Conversation

@glbrntt
Copy link
Collaborator

@glbrntt glbrntt commented Jan 18, 2024

Motivation:

Servers must manage connections created by clients. Part of this is gracefully closing connections (by sending GOAWAY frames and ratcheting down the last stream ID) in response to various conditions: the client sending too many pings, the connection being idle too long, the connection existing for longer than some configured limit, etc.

A previous change added a state machine which handles much of this behaviour. This change adds a channel handler which builds on top of that state machine.

Modifications:

  • Add a channel handler for managing connections on the server.

Result:

We have a handler in place which can manage connections on the server.

Motivation:

Servers must manage connections created by clients. Part of this is
gracefully closing connections (by sending GOAWAY frames and ratcheting
down the last stream ID) in response to various conditions: the client
sending too many pings, the connection being idle too long, the
connection existing for longer than some configured limit, etc.

A previous change added a state machine which handles much of this
behaviour. This change adds a channel handler which builds on top of
that state machine.

Modifications:

- Add a channel handler for managing connections on the server.

Result:

We have a handler in place which can manage connections on the server.
@glbrntt glbrntt added the version/v2 Relates to v2 label Jan 18, 2024
}

func channelRead(context: ChannelHandlerContext, data: NIOAny) {
self.inReadLoop = true
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding this comment here but it applies to more of this PR. Why do we have some state management inside a state machine but that some state managed as vars of this handler. It isn't clear to me where that separation goes and it feels to me like we should have a single state machine for this handler that handles all the state.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layering, mostly. Most of the state within the handler that isn't the state machine are triggers which prod the state machine. Storing timers etc., back in the state machine complicates the state machine more than it helps. As for the flushing etc, it's not related to connection management, it's its own separate set of state.

Copy link
Collaborator

@stefanadranca stefanadranca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

Copy link
Collaborator

@gjcairo gjcairo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just left a nit and a question.

Comment on lines +342 to +344
while self.flushPending {
self.flushPending = false
context.flush()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more of a NIO question but want to double check: context.flush() will start by calling self.flush() in this case, right? Which would in turn call maybeFlush(context:), which can reset flushPending to be true again.
I just want to make sure I understand why we're checking for flushPending in a while loop.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, context.flush() will call flush(context:) on the next channel handler.

We're calling it in a loop here in case a flush re-entrantly triggers another write which could set flushPending back to true.

glbrntt and others added 2 commits January 22, 2024 11:21
Co-authored-by: Stefana-Ioana Dranca <66513820+stefanadranca@users.noreply.github.com>
Co-authored-by: Gustavo Cairo <me@gustavocairo.com>
@glbrntt glbrntt merged commit 941f500 into grpc:main Jan 22, 2024
@glbrntt glbrntt deleted the server-connection-handler branch January 22, 2024 14:08
glbrntt added a commit to glbrntt/grpc-swift that referenced this pull request Feb 5, 2024
Motivation:

Servers must manage connections created by clients. Part of this is
gracefully closing connections (by sending GOAWAY frames and ratcheting
down the last stream ID) in response to various conditions: the client
sending too many pings, the connection being idle too long, the
connection existing for longer than some configured limit, etc.

A previous change added a state machine which handles much of this
behaviour. This change adds a channel handler which builds on top of
that state machine.

Modifications:

- Add a channel handler for managing connections on the server.

Result:

We have a handler in place which can manage connections on the server.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

version/v2 Relates to v2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants