-
-
Notifications
You must be signed in to change notification settings - Fork 79
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
Fix crash in PoolStateMachine+ConnectionGroup when closing connection while keepAlive is running #444
Fix crash in PoolStateMachine+ConnectionGroup when closing connection while keepAlive is running #444
Changes from 1 commit
85805a6
68f7c07
8ae5614
4673908
4f733d6
40816ec
b50c32e
d009cc1
d650071
e7b8770
e0438af
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -449,6 +449,21 @@ extension PoolStateMachine { | |
return (index, context) | ||
} | ||
|
||
/// Returns `true` if the connection should be explicitly closed, `false` if nothing needs to be done. | ||
@inlinable | ||
mutating func keepAliveFailed(_ connectionID: Connection.ID) -> Bool { | ||
// We don't have to inform the ConnectionStates about any of this, because the connection will close | ||
// immediately after this or is closed already | ||
switch self.connections.first(where: { $0.id == connectionID })?.state { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please don‘t access the connection‘s state here. the state is only visible here, to allow inlining. Instead please forward a call keepAliveFailed into the ConnectionStateMachine. Also make sure to change the state to closing, if we need to explicitly close the connection. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The connection state is receiving the failure now and changes the state accordingly. |
||
case .closing, .closed, .none: | ||
// There might've been a race between closing and keeping the connection alive. | ||
// The connection has already been closed in that case. | ||
return false | ||
default: | ||
return true | ||
} | ||
} | ||
|
||
// MARK: Connection close/removal | ||
|
||
@usableFromInline | ||
|
@@ -547,8 +562,9 @@ extension PoolStateMachine { | |
|
||
if closedAction.wasRunningKeepAlive { | ||
self.stats.runningKeepAlive -= 1 | ||
} else { | ||
lovetodream marked this conversation as resolved.
Show resolved
Hide resolved
|
||
self.stats.leasedStreams -= closedAction.usedStreams | ||
} | ||
self.stats.leasedStreams -= closedAction.usedStreams | ||
self.stats.availableStreams -= closedAction.maxStreams - closedAction.usedStreams | ||
|
||
switch closedAction.previousConnectionState { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -374,6 +374,14 @@ struct PoolStateMachine< | |
return self.handleAvailableConnection(index: index, availableContext: context) | ||
} | ||
|
||
@inlinable | ||
mutating func connectionKeepAliveFailed(_ connection: Connection) -> Action { | ||
if self.connections.keepAliveFailed(connection.id) { | ||
return self.connectionClosed(connection) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That doesn‘t look right, if we the keep alive failed, we can‘t declare the connection dead right away, we need to create a close action. Also if we close and have waiting requests, we might need to create a new connection right away. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The connection is now properly closed by reusing the existing closed states and actions. I've added a test to ensure a new connection is established if required. |
||
} | ||
return .none() | ||
} | ||
|
||
@inlinable | ||
mutating func connectionIdleTimerTriggered(_ connectionID: ConnectionID) -> Action { | ||
precondition(self.requestQueue.isEmpty) | ||
|
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.
Can we return an enum for this? KeepAliveFailedAction with two cases: close and none? Makes this more explicit
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 is now returning an optional CloseAction. It should be explicit enough now, let me know if not.