mirror of
https://github.com/swift-server/async-http-client.git
synced 2026-06-02 07:37:34 +00:00
Fix sendability issues in the connection pool (#833)
Motivation: The connection pool holds much of the low level logic in AHC. We should fix its sendability issues before moving to higher levels. Modifications: - Make HTTP1ConnectionDelegate and HTTP2Delegate sendable, this requires passing IDs rather than connections to their methods - Make HTTPConnectionRequester sendable and have its methods take Sendable views of the HTTP1Connection and HTTP2Connection types - Add sendable views to HTTP1Connection and HTTP2Connection - Mark HTTP1Connection and HTTP2Connection as not sendable - Make HTTPRequestExecutor and HTTPExecutableRequest sendable - Update tests Result: Connection pool has stricter sendability requirements
This commit is contained in:
@@ -137,7 +137,7 @@ final class HTTP2ClientRequestHandler: ChannelDuplexHandler {
|
||||
self.runTimeoutAction(timeoutAction, context: context)
|
||||
}
|
||||
|
||||
request.willExecuteRequest(self)
|
||||
request.willExecuteRequest(self.requestExecutor)
|
||||
|
||||
let action = self.state.startRequest(
|
||||
head: request.requestHead,
|
||||
@@ -313,7 +313,7 @@ final class HTTP2ClientRequestHandler: ChannelDuplexHandler {
|
||||
assert(self.idleReadTimeoutTimer == nil, "Expected there is no timeout timer so far.")
|
||||
|
||||
let timerID = self.currentIdleReadTimeoutTimerID
|
||||
self.idleReadTimeoutTimer = self.eventLoop.scheduleTask(in: timeAmount) {
|
||||
self.idleReadTimeoutTimer = self.eventLoop.assumeIsolated().scheduleTask(in: timeAmount) {
|
||||
guard self.currentIdleReadTimeoutTimerID == timerID else { return }
|
||||
let action = self.state.idleReadTimeoutTriggered()
|
||||
self.run(action, context: context)
|
||||
@@ -326,7 +326,7 @@ final class HTTP2ClientRequestHandler: ChannelDuplexHandler {
|
||||
|
||||
self.currentIdleReadTimeoutTimerID &+= 1
|
||||
let timerID = self.currentIdleReadTimeoutTimerID
|
||||
self.idleReadTimeoutTimer = self.eventLoop.scheduleTask(in: timeAmount) {
|
||||
self.idleReadTimeoutTimer = self.eventLoop.assumeIsolated().scheduleTask(in: timeAmount) {
|
||||
guard self.currentIdleReadTimeoutTimerID == timerID else { return }
|
||||
let action = self.state.idleReadTimeoutTriggered()
|
||||
self.run(action, context: context)
|
||||
@@ -349,7 +349,7 @@ final class HTTP2ClientRequestHandler: ChannelDuplexHandler {
|
||||
assert(self.idleWriteTimeoutTimer == nil, "Expected there is no timeout timer so far.")
|
||||
|
||||
let timerID = self.currentIdleWriteTimeoutTimerID
|
||||
self.idleWriteTimeoutTimer = self.eventLoop.scheduleTask(in: timeAmount) {
|
||||
self.idleWriteTimeoutTimer = self.eventLoop.assumeIsolated().scheduleTask(in: timeAmount) {
|
||||
guard self.currentIdleWriteTimeoutTimerID == timerID else { return }
|
||||
let action = self.state.idleWriteTimeoutTriggered()
|
||||
self.run(action, context: context)
|
||||
@@ -361,7 +361,7 @@ final class HTTP2ClientRequestHandler: ChannelDuplexHandler {
|
||||
|
||||
self.currentIdleWriteTimeoutTimerID &+= 1
|
||||
let timerID = self.currentIdleWriteTimeoutTimerID
|
||||
self.idleWriteTimeoutTimer = self.eventLoop.scheduleTask(in: timeAmount) {
|
||||
self.idleWriteTimeoutTimer = self.eventLoop.assumeIsolated().scheduleTask(in: timeAmount) {
|
||||
guard self.currentIdleWriteTimeoutTimerID == timerID else { return }
|
||||
let action = self.state.idleWriteTimeoutTriggered()
|
||||
self.run(action, context: context)
|
||||
@@ -437,43 +437,39 @@ final class HTTP2ClientRequestHandler: ChannelDuplexHandler {
|
||||
@available(*, unavailable)
|
||||
extension HTTP2ClientRequestHandler: Sendable {}
|
||||
|
||||
extension HTTP2ClientRequestHandler: HTTPRequestExecutor {
|
||||
func writeRequestBodyPart(_ data: IOData, request: HTTPExecutableRequest, promise: EventLoopPromise<Void>?) {
|
||||
if self.eventLoop.inEventLoop {
|
||||
self.writeRequestBodyPart0(data, request: request, promise: promise)
|
||||
} else {
|
||||
self.eventLoop.execute {
|
||||
self.writeRequestBodyPart0(data, request: request, promise: promise)
|
||||
}
|
||||
}
|
||||
extension HTTP2ClientRequestHandler {
|
||||
var requestExecutor: RequestExecutor {
|
||||
RequestExecutor(self)
|
||||
}
|
||||
|
||||
func finishRequestBodyStream(_ request: HTTPExecutableRequest, promise: EventLoopPromise<Void>?) {
|
||||
if self.eventLoop.inEventLoop {
|
||||
self.finishRequestBodyStream0(request, promise: promise)
|
||||
} else {
|
||||
self.eventLoop.execute {
|
||||
self.finishRequestBodyStream0(request, promise: promise)
|
||||
struct RequestExecutor: HTTPRequestExecutor, Sendable {
|
||||
private let loopBound: NIOLoopBound<HTTP2ClientRequestHandler>
|
||||
|
||||
init(_ handler: HTTP2ClientRequestHandler) {
|
||||
self.loopBound = NIOLoopBound(handler, eventLoop: handler.eventLoop)
|
||||
}
|
||||
|
||||
func writeRequestBodyPart(_ data: IOData, request: HTTPExecutableRequest, promise: EventLoopPromise<Void>?) {
|
||||
self.loopBound.execute {
|
||||
$0.writeRequestBodyPart0(data, request: request, promise: promise)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func demandResponseBodyStream(_ request: HTTPExecutableRequest) {
|
||||
if self.eventLoop.inEventLoop {
|
||||
self.demandResponseBodyStream0(request)
|
||||
} else {
|
||||
self.eventLoop.execute {
|
||||
self.demandResponseBodyStream0(request)
|
||||
func finishRequestBodyStream(_ request: HTTPExecutableRequest, promise: EventLoopPromise<Void>?) {
|
||||
self.loopBound.execute {
|
||||
$0.finishRequestBodyStream0(request, promise: promise)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func cancelRequest(_ request: HTTPExecutableRequest) {
|
||||
if self.eventLoop.inEventLoop {
|
||||
self.cancelRequest0(request)
|
||||
} else {
|
||||
self.eventLoop.execute {
|
||||
self.cancelRequest0(request)
|
||||
func demandResponseBodyStream(_ request: HTTPExecutableRequest) {
|
||||
self.loopBound.execute {
|
||||
$0.demandResponseBodyStream0(request)
|
||||
}
|
||||
}
|
||||
|
||||
func cancelRequest(_ request: HTTPExecutableRequest) {
|
||||
self.loopBound.execute {
|
||||
$0.cancelRequest0(request)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user