Skip to content

Strict Concurrency#98

Merged
rnro merged 16 commits intomainfrom
strict_concurrency_only
Apr 10, 2025
Merged

Strict Concurrency#98
rnro merged 16 commits intomainfrom
strict_concurrency_only

Conversation

@rnro
Copy link
Copy Markdown
Contributor

@rnro rnro commented Apr 7, 2025

Motivation

Make the examples strict concurrency safe and lock-in those changes with CI.

Modifications

  • Resolve strict concurrency issues
  • Add opt-in strict concurrency settings to package manifests
  • Add always-on strict concurrency settings to the Xcode project for NIOSMTP when built in debug mode (!)
  • Remove nio-launchd from Linux CI since it requires a Darwin platform

Result

  • Concurrency-safe code

@rnro rnro changed the title Strict concurrency only Strict Concurrency Apr 7, 2025
@rnro rnro force-pushed the strict_concurrency_only branch from 22a75e9 to fd717f7 Compare April 7, 2025 15:23
@rnro rnro marked this pull request as ready for review April 7, 2025 16:38
@rnro rnro requested a review from glbrntt April 7, 2025 16:38
@rnro rnro enabled auto-merge (squash) April 7, 2025 16:39
Comment thread TLSify/Sources/TLSifyLib/TLSProxy.swift Outdated

do {
try myChannel.pipeline.syncOperations.addHandler(myGlue, position: .after(contextForInitialData.handler))
_ = try partnerChannel.pipeline.syncOperations.handler(type: CloseOnErrorHandler.self)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why are we getting the handler and throwing it away?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The previous code seemed to do effectively that

        {
            partnerChannel.pipeline.handler(type: CloseOnErrorHandler.self)
        }.flatMap { errorHandler in
            partnerChannel.pipeline.addHandler(partnerGlue)
        }

Maybe it was doing for some side-effect or maybe it was leftover code? I guess either way now it's synchronous I guess I can just delete line 98 now.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I suspect the glue handler was meant to be added before the error handler. Normally the close-on-error handler would be the last in the pipeline.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It looks like it is currently inserted after ChannelHandlerContext.handler where the context passed along after the error handler has been inserted, I can't work out from a glance at the code what that actually represents.

In my current changes I have just removed that line on 98. Should I change

try myChannel.pipeline.syncOperations.addHandler(myGlue, position: .after(contextForInitialData.handler))

to

let closeErrorHandler = try partnerChannel.pipeline.syncOperations.handler(type: CloseOnErrorHandler.self)
try myChannel.pipeline.syncOperations.addHandler(myGlue, position: .before(closeErrorHandler))

peerChannel.close(mode: .all, promise: nil)
context.close(promise: nil)
}
context.pipeline.syncOperations.removeHandler(self, promise: nil)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This was only done on the success path before

context.pipeline.removeHandler(context: $0, promise: nil)
}

let byteToMessageHandlerContext = try! context.pipeline.syncOperations.context(handlerType: ByteToMessageHandler<HTTPRequestDecoder>.self)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The previous code didn't blow up if the context couldn't be found

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've made this no longer blow up but only remove the handler if it can be found.

context.pipeline.context(handlerType: HTTPResponseEncoder.self).whenSuccess {
context.pipeline.removeHandler(context: $0, promise: nil)
}
let httpResponseEncoderContext = try! context.pipeline.syncOperations.context(handlerType: HTTPResponseEncoder.self)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've made this no longer blow up but only remove the handler if it can be found.

Comment thread http2-server/Sources/http2-server/main.swift
return context.channel.writeAndFlush(self.wrapOutboundOut(HTTPServerResponsePart.end(nil)))
}.whenComplete { _ in
context.channel.write(HTTPServerResponsePart.body(.byteBuffer(buffer)), promise: nil)
_ = context.channel.writeAndFlush(HTTPServerResponsePart.end(nil))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The close was chain off of the write-and-flush before, now it isn't. It should either be chained off of it or we should pass promise: nil to writeAndFlush

import Foundation

public enum ResultType<Value, Error> {
public enum ResultType<Value, Error>: Sendable where Value: Sendable, Error: Sendable {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This shows its age 😄

Comment thread NIOSMTP/NIOSMTP/Configuration.swift Outdated
Comment on lines +27 to +30
var serverConfig: ServerConfiguration? = nil
guard let serverConfig = serverConfig else {
fatalError("You need to configure an SMTP server in code.")
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

... this isn't gonna work.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The intention was for it to fatal error in this case. I've changed this to be a precondition failure instead which is hopefully more obvious

Comment thread http-responsiveness-server/Package.swift
Comment thread .github/workflows/pull_request.yml Outdated
run: echo "build-test-matrix=$(curl -s https://raw.githubusercontent.com/apple/swift-nio/main/scripts/generate_matrix.sh | bash)" >> "$GITHUB_OUTPUT"
env:
MATRIX_LINUX_COMMAND: STRICT_CONCURRENCY=true SWIFT_PACKAGE_DIRECTORIES='TLSify UniversalBootstrapDemo http-responsiveness-server connect-proxy http2-client http2-server json-rpc nio-launchd' dev/build_all.sh && SWIFT_PACKAGE_DIRECTORIES='backpressure-file-io-channel' dev/build_all.sh
MATRIX_LINUX_COMMAND: STRICT_CONCURRENCY=true SWIFT_PACKAGE_DIRECTORIES='TLSify UniversalBootstrapDemo http-responsiveness-server connect-proxy http2-client http2-server json-rpc' dev/build_all.sh && SWIFT_PACKAGE_DIRECTORIES='backpressure-file-io-channel' dev/build_all.sh
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Rather than removing it, it probably makes more sense to update the example so that when compiling on linux it's a no-op or prints a message saying it's a Darwin only or similar.

@rnro rnro requested a review from glbrntt April 8, 2025 12:27
Comment thread backpressure-file-io-channel/Sources/BackpressureChannelToFileIODemo/main.swift Outdated
context.close(promise: nil)
}
}
#endif
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do you need an else which prints an warning that this is Darwin only?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oh yeah, that's fine.

…IODemo/main.swift

Co-authored-by: George Barnett <gbarnett@apple.com>
@rnro rnro requested a review from glbrntt April 10, 2025 10:08
@rnro rnro merged commit c06a18c into main Apr 10, 2025
15 checks passed
@rnro rnro deleted the strict_concurrency_only branch April 10, 2025 11:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants