-
Notifications
You must be signed in to change notification settings - Fork 656
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
Enable strict concurrency checking for NIOHTTP1 #3115
Conversation
9f4bfc7
to
71328d5
Compare
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, thanks Rick!
Motivation: To ensure NIOHTTP1 concurrency safety. Modifications: * Enable strict concurrency checking in the package manifest. * Mark several objects `Sendable` with `@preconcurrency` annotations where they are returned in futures which may execute in arbitrary concurrency domains. * `HTTPServerProtocolUpgrader` * `NIOHTTPClientProtocolUpgrader` * `NIOTypedHTTPClientProtocolUpgrader` * `NIOUpgradableHTTPServerPipelineConfiguration` * `NIOUpgradableHTTPClientPipelineConfiguration` * `NIOTypedHTTPClientUpgradeConfiguration` * Mark handlers as explicitly not sendable * `NIOTypedHTTPClientUpgradeHandler` * `NIOTypedHTTPServerUpgradeHandler` Result: No more concurrency warnings. Builds will warn and CI will fail if regressions are introduced.
* Make use of `assumeIsolated` instead of `NIOLoopBound`s * Do not add `Sendable` requirement to `NIOHTTPClientProtocolUpgrader` * Do not add `Sendable` requirement to `HTTPServerProtocolUpgrader`
58292a9
to
073e64e
Compare
return { | ||
self.upgradeState = .upgrading | ||
|
||
// assumeIsolated is safe here because this is only called from channelRead |
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.
Isn't the justification here that removeHTTPHandlers
returns us a future on the right EL? Should it be modified to return an isolated ELF? Otherwise the guarantee is based on documentation vs types.
upgrader: any NIOTypedHTTPServerProtocolUpgrader<UpgradeResult>, responseHeaders: HTTPHeaders, | ||
proto: String |
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.
Given the weird formatting can we do one param per line?
upgrader: any NIOTypedHTTPServerProtocolUpgrader<UpgradeResult>, responseHeaders: HTTPHeaders, | |
proto: String | |
upgrader: any NIOTypedHTTPServerProtocolUpgrader<UpgradeResult>, | |
responseHeaders: HTTPHeaders, | |
proto: String |
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 one got a thumbs up but no action 🤷♂️
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.
Sorry, there must have been more than one instance or something - I definitely tweaked formatting in code that looked like this 4a5073e#diff-df1f0e00e4593ea99b5fed7e3a37f6415e9531d25dcb6994d6ba0f0a8ecf6cebR316
/// - Returns: An `EventLoopFuture` that will contain a callback to invoke if upgrade is requested, or nil if upgrade has failed. Never returns a failed future. | ||
/// - Returns: An isolated `EventLoopFuture` that will contain a callback to invoke if upgrade is requested, | ||
/// or nil if upgrade has failed. Never returns a failed future. | ||
/// The `NIOLoopBound` is safe because it's only called after the hop in firstRequestHeadReceived |
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.
What NIOLoopBound
?
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 left over from a previous implementation- removed.
@@ -18,7 +18,8 @@ import NIOCore | |||
|
|||
/// Configuration for an upgradable HTTP pipeline. | |||
@available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) | |||
public struct NIOUpgradableHTTPServerPipelineConfiguration<UpgradeResult: Sendable> { | |||
@preconcurrency |
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.
No need for a preconcurrency annotation here.
@@ -146,7 +147,8 @@ extension ChannelPipeline.SynchronousOperations { | |||
|
|||
/// Configuration for an upgradable HTTP pipeline. | |||
@available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) | |||
public struct NIOUpgradableHTTPClientPipelineConfiguration<UpgradeResult: Sendable> { | |||
@preconcurrency |
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.
No need for a preconcurrency annotation here.
@@ -42,7 +43,8 @@ public protocol NIOTypedHTTPClientProtocolUpgrader<UpgradeResult> { | |||
|
|||
/// The upgrade configuration for the ``NIOTypedHTTPClientUpgradeHandler``. | |||
@available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) | |||
public struct NIOTypedHTTPClientUpgradeConfiguration<UpgradeResult: Sendable> { | |||
@preconcurrency |
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.
No need for a preconcurrency
annotation here.
@@ -47,7 +48,8 @@ public protocol NIOTypedHTTPServerProtocolUpgrader<UpgradeResult> { | |||
|
|||
/// The upgrade configuration for the ``NIOTypedHTTPServerUpgradeHandler``. | |||
@available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) | |||
public struct NIOTypedHTTPServerUpgradeConfiguration<UpgradeResult: Sendable> { | |||
@preconcurrency |
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.
No need for preconcurrency
annotation here.
}.flatMap { () -> EventLoopFuture<UpgradeResult> in | ||
upgrader.upgrade(channel: channel, upgradeRequest: requestHead) | ||
}.nonisolated().hop(to: context.eventLoop) | ||
.assumeIsolated() |
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.
nonisolated().hop(to:).assumeIsolated()
shouldn't do anything meaningful here. We were already isolated.
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.
Nice one. Merging over the API breakage checker as that's expected.
Motivation:
To ensure NIOHTTP1 concurrency safety.
Modifications:
Sendable
with@preconcurrency
annotations where they are returned in futures which may execute in arbitrary concurrency domains.NIOTypedHTTPClientProtocolUpgrader
NIOTypedHTTPClientUpgradeConfiguration
NIOUpgradableHTTPServerPipelineConfiguration
NIOUpgradableHTTPClientPipelineConfiguration
NIOTypedHTTPServerProtocolUpgrader
NIOTypedHTTPServerUpgradeConfiguration
NIOTypedHTTPClientUpgradeHandler
NIOTypedHTTPServerUpgradeHandler
NIOHTTPClientUpgradeSendableConfiguration
NIOHTTPServerUpgradeSendableConfiguration
Result:
No more concurrency warnings. Builds will warn and CI will fail if regressions are introduced.