Skip to content

Commit 75b390e

Browse files
authored
Adopt h2handler multiplexer (grpc#1587)
Motivation: Switch from `HTTP2StreamMultiplexer` to `HTTP2Handler.StreamMultiplexer` to benefit from improved performance due to reduced allocations. Modifications: - Replace all references to `HTTP2StreamMultiplexer` with `HTTP2Handler.StreamMultiplexer`. - `GRPCIdleHandler` is now a `NIOHTTP2StreamDelegate` to allow it to receive notifications when a stream is created or closed rather than using `UserInboundEvent`s. - `GRPCIdleHandler` now has two states of configuration in the client case. This is required to break a cycle of dependencies which would otherwise exist at `init` because the `GRPCIdleHandler` holds a reference to the `HTTP2Handler.StreamMultiplexer` (which is a member of the `HTTP2Handler` itself) and the `HTTP2Handler` holds a reference back to the `GRPCIdleHandler` as its stream delegate. - Several tests now insert `HTTP2Handler` into the pipeline where they used to use `HTTP2StreamMultiplexer`. This causes a few changes in behavior often around different assertions. This required some small supporting changes. - Introduce test infrastructure `AsyncEventStreamConnectionPoolDelegate` to eliminate observed racey behavior in `EventRecordingConnectionPoolDelegate`. Result: Performance increase without Overall behavior changes.
1 parent 87fa9ed commit 75b390e

18 files changed

+867
-484
lines changed

Diff for: .github/workflows/ci.yaml

+20-20
Original file line numberDiff line numberDiff line change
@@ -57,44 +57,44 @@ jobs:
5757
include:
5858
- image: swiftlang/swift:nightly-focal
5959
env:
60-
MAX_ALLOCS_ALLOWED_bidi_1k_rpcs_10_requests: 347000
61-
MAX_ALLOCS_ALLOWED_bidi_1k_rpcs_1_request: 167000
60+
MAX_ALLOCS_ALLOWED_bidi_1k_rpcs_10_requests: 246000
61+
MAX_ALLOCS_ALLOWED_bidi_1k_rpcs_1_request: 138000
6262
MAX_ALLOCS_ALLOWED_embedded_server_bidi_1k_rpcs_10_small_requests: 109000
6363
MAX_ALLOCS_ALLOWED_embedded_server_bidi_1k_rpcs_1_small_request: 64000
6464
MAX_ALLOCS_ALLOWED_embedded_server_unary_1k_rpcs_1_small_request: 60000
65-
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong: 169000
66-
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong_interceptors_client: 176000
67-
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong_interceptors_server: 176000
65+
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong: 129000
66+
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong_interceptors_client: 136000
67+
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong_interceptors_server: 136000
6868
- image: swift:5.8-jammy
6969
env:
70-
MAX_ALLOCS_ALLOWED_bidi_1k_rpcs_10_requests: 347000
71-
MAX_ALLOCS_ALLOWED_bidi_1k_rpcs_1_request: 167000
70+
MAX_ALLOCS_ALLOWED_bidi_1k_rpcs_10_requests: 246000
71+
MAX_ALLOCS_ALLOWED_bidi_1k_rpcs_1_request: 138000
7272
MAX_ALLOCS_ALLOWED_embedded_server_bidi_1k_rpcs_10_small_requests: 109000
7373
MAX_ALLOCS_ALLOWED_embedded_server_bidi_1k_rpcs_1_small_request: 64000
7474
MAX_ALLOCS_ALLOWED_embedded_server_unary_1k_rpcs_1_small_request: 60000
75-
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong: 169000
76-
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong_interceptors_client: 176000
77-
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong_interceptors_server: 176000
75+
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong: 129000
76+
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong_interceptors_client: 136000
77+
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong_interceptors_server: 136000
7878
- image: swift:5.7-jammy
7979
env:
80-
MAX_ALLOCS_ALLOWED_bidi_1k_rpcs_10_requests: 347000
81-
MAX_ALLOCS_ALLOWED_bidi_1k_rpcs_1_request: 167000
80+
MAX_ALLOCS_ALLOWED_bidi_1k_rpcs_10_requests: 246000
81+
MAX_ALLOCS_ALLOWED_bidi_1k_rpcs_1_request: 138000
8282
MAX_ALLOCS_ALLOWED_embedded_server_bidi_1k_rpcs_10_small_requests: 109000
8383
MAX_ALLOCS_ALLOWED_embedded_server_bidi_1k_rpcs_1_small_request: 64000
8484
MAX_ALLOCS_ALLOWED_embedded_server_unary_1k_rpcs_1_small_request: 60000
85-
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong: 169000
86-
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong_interceptors_client: 176000
87-
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong_interceptors_server: 176000
85+
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong: 129000
86+
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong_interceptors_client: 136000
87+
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong_interceptors_server: 136000
8888
- image: swift:5.6-focal
8989
env:
90-
MAX_ALLOCS_ALLOWED_bidi_1k_rpcs_10_requests: 348000
91-
MAX_ALLOCS_ALLOWED_bidi_1k_rpcs_1_request: 168000
90+
MAX_ALLOCS_ALLOWED_bidi_1k_rpcs_10_requests: 247000
91+
MAX_ALLOCS_ALLOWED_bidi_1k_rpcs_1_request: 139000
9292
MAX_ALLOCS_ALLOWED_embedded_server_bidi_1k_rpcs_10_small_requests: 109000
9393
MAX_ALLOCS_ALLOWED_embedded_server_bidi_1k_rpcs_1_small_request: 64000
9494
MAX_ALLOCS_ALLOWED_embedded_server_unary_1k_rpcs_1_small_request: 60000
95-
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong: 170000
96-
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong_interceptors_client: 177000
97-
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong_interceptors_server: 177000
95+
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong: 130000
96+
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong_interceptors_client: 137000
97+
MAX_ALLOCS_ALLOWED_unary_1k_ping_pong_interceptors_server: 137000
9898

9999
name: Performance Tests on ${{ matrix.image }}
100100
runs-on: ubuntu-latest

Diff for: NOTICES.txt

+8
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,11 @@ framework: 'test_01_allocation_counts.sh', 'run-nio-alloc-counter-tests.sh' and
2525
* https://github.com/apple/swift-nio/blob/main/LICENSE.txt
2626
* HOMEPAGE:
2727
* https://github.com/apple/swift-nio
28+
29+
This product contains a simplified derivation of SwiftNIO HTTP/2's
30+
'HTTP2FrameEncoder' for testing purposes.
31+
32+
* LICENSE (Apache License 2.0):
33+
* https://github.com/apple/swift-nio-http2/blob/main/LICENSE.txt
34+
* HOMEPAGE:
35+
* https://github.com/apple/swift-nio-http2

Diff for: Package.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ let packageDependencies: [Package.Dependency] = [
3636
),
3737
.package(
3838
url: "https://github.com/apple/swift-nio-http2.git",
39-
from: "1.24.1"
39+
from: "1.26.0"
4040
),
4141
.package(
4242
url: "https://github.com/apple/swift-nio-transport-services.git",

Diff for: Sources/GRPC/ClientConnection.swift

+48-43
Original file line numberDiff line numberDiff line change
@@ -53,28 +53,25 @@ import SwiftProtobuf
5353
/// │ DelegatingErrorHandler │
5454
/// └──────────▲───────────────┘
5555
/// HTTP2Frame│
56-
/// │ ⠇ ⠇ ⠇ ⠇
57-
/// │ ┌┴─▼┐ ┌┴─▼┐
58-
/// │ │ | │ | HTTP/2 streams
59-
/// │ └▲─┬┘ └▲─┬┘
60-
/// │ │ │ │ │ HTTP2Frame
61-
/// ┌─┴────────────────┴─▼───┴─▼┐
62-
/// │ HTTP2StreamMultiplexer |
63-
/// └─▲───────────────────────┬─┘
64-
/// HTTP2Frame│ │HTTP2Frame
65-
/// ┌─┴───────────────────────▼─┐
66-
/// │ GRPCIdleHandler │
67-
/// └─▲───────────────────────┬─┘
68-
/// HTTP2Frame│ │HTTP2Frame
69-
/// ┌─┴───────────────────────▼─┐
70-
/// │ NIOHTTP2Handler │
71-
/// └─▲───────────────────────┬─┘
72-
/// ByteBuffer│ │ByteBuffer
73-
/// ┌─┴───────────────────────▼─┐
74-
/// │ NIOSSLHandler │
75-
/// └─▲───────────────────────┬─┘
76-
/// ByteBuffer│ │ByteBuffer
77-
/// │ ▼
56+
/// │
57+
/// │
58+
/// │
59+
/// │
60+
/// │
61+
/// HTTP2Frame│ ⠇ ⠇ ⠇ ⠇ ⠇
62+
/// ┌─┴──────────────────▼─┐ ┌┴─▼┐ ┌┴─▼┐
63+
/// │ GRPCIdleHandler │ │ | │ | HTTP/2 streams
64+
/// └─▲──────────────────┬─┘ └▲─┬┘ └▲─┬┘
65+
/// HTTP2Frame│ │ │ │ │ │ HTTP2Frame
66+
/// ┌─┴──────────────────▼────────┴─▼───┴─▼┐
67+
/// │ NIOHTTP2Handler │
68+
/// └─▲──────────────────────────────────┬─┘
69+
/// ByteBuffer│ │ByteBuffer
70+
/// ┌─┴──────────────────────────────────▼─┐
71+
/// │ NIOSSLHandler │
72+
/// └─▲──────────────────────────────────┬─┘
73+
/// ByteBuffer│ │ByteBuffer
74+
/// │ ▼
7875
///
7976
/// The 'GRPCIdleHandler' intercepts HTTP/2 frames and various events and is responsible for
8077
/// informing and controlling the state of the connection (idling and keepalive). The HTTP/2 streams
@@ -83,7 +80,7 @@ public final class ClientConnection: Sendable {
8380
private let connectionManager: ConnectionManager
8481

8582
/// HTTP multiplexer from the underlying channel handling gRPC calls.
86-
internal func getMultiplexer() -> EventLoopFuture<HTTP2StreamMultiplexer> {
83+
internal func getMultiplexer() -> EventLoopFuture<NIOHTTP2Handler.StreamMultiplexer> {
8784
return self.connectionManager.getHTTP2Multiplexer()
8885
}
8986

@@ -245,7 +242,7 @@ extension ClientConnection: GRPCChannel {
245242
}
246243

247244
private static func makeStreamChannel(
248-
using result: Result<HTTP2StreamMultiplexer, Error>,
245+
using result: Result<NIOHTTP2Handler.StreamMultiplexer, Error>,
249246
promise: EventLoopPromise<Channel>
250247
) {
251248
switch result {
@@ -606,29 +603,31 @@ extension ChannelPipeline.SynchronousOperations {
606603
HTTP2Setting(parameter: .initialWindowSize, value: httpTargetWindowSize),
607604
]
608605

609-
// We could use 'configureHTTP2Pipeline' here, but we need to add a few handlers between the
610-
// two HTTP/2 handlers so we'll do it manually instead.
611-
try self.addHandler(NIOHTTP2Handler(mode: .client, initialSettings: initialSettings))
612-
613-
let h2Multiplexer = HTTP2StreamMultiplexer(
614-
mode: .client,
615-
channel: channel,
616-
targetWindowSize: httpTargetWindowSize,
617-
inboundStreamInitializer: nil
618-
)
619-
620-
// The multiplexer is passed through the idle handler so it is only reported on
621-
// successful channel activation - with happy eyeballs multiple pipelines can
622-
// be constructed so it's not safe to report just yet.
623-
try self.addHandler(GRPCIdleHandler(
606+
let grpcIdleHandler = GRPCIdleHandler(
624607
connectionManager: connectionManager,
625-
multiplexer: h2Multiplexer,
626608
idleTimeout: connectionIdleTimeout,
627609
keepalive: connectionKeepalive,
628610
logger: logger
629-
))
611+
)
612+
613+
var connectionConfiguration = NIOHTTP2Handler.ConnectionConfiguration()
614+
connectionConfiguration.initialSettings = initialSettings
615+
var streamConfiguration = NIOHTTP2Handler.StreamConfiguration()
616+
streamConfiguration.targetWindowSize = httpTargetWindowSize
617+
let h2Handler = NIOHTTP2Handler(
618+
mode: .client,
619+
eventLoop: channel.eventLoop,
620+
connectionConfiguration: connectionConfiguration,
621+
streamConfiguration: streamConfiguration,
622+
streamDelegate: grpcIdleHandler
623+
) { channel in
624+
channel.close()
625+
}
626+
try self.addHandler(h2Handler)
627+
628+
grpcIdleHandler.setMultiplexer(try h2Handler.syncMultiplexer())
629+
try self.addHandler(grpcIdleHandler)
630630

631-
try self.addHandler(h2Multiplexer)
632631
try self.addHandler(DelegatingErrorHandler(logger: logger, delegate: errorDelegate))
633632
}
634633
}
@@ -638,7 +637,13 @@ extension Channel {
638637
errorDelegate: ClientErrorDelegate?,
639638
logger: Logger
640639
) -> EventLoopFuture<Void> {
641-
return self.configureHTTP2Pipeline(mode: .client, inboundStreamInitializer: nil).flatMap { _ in
640+
return self.configureHTTP2Pipeline(
641+
mode: .client,
642+
connectionConfiguration: .init(),
643+
streamConfiguration: .init()
644+
) { channel in
645+
channel.eventLoop.makeSucceededVoidFuture()
646+
}.flatMap { _ in
642647
self.pipeline.addHandler(DelegatingErrorHandler(logger: logger, delegate: errorDelegate))
643648
}
644649
}

Diff for: Sources/GRPC/ConnectionManager.swift

+23-18
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,23 @@ internal final class ConnectionManager: @unchecked Sendable {
3535
var reconnect: Reconnect
3636

3737
var candidate: EventLoopFuture<Channel>
38-
var readyChannelMuxPromise: EventLoopPromise<HTTP2StreamMultiplexer>
39-
var candidateMuxPromise: EventLoopPromise<HTTP2StreamMultiplexer>
38+
var readyChannelMuxPromise: EventLoopPromise<NIOHTTP2Handler.StreamMultiplexer>
39+
var candidateMuxPromise: EventLoopPromise<NIOHTTP2Handler.StreamMultiplexer>
4040
}
4141

4242
internal struct ConnectedState {
4343
var backoffIterator: ConnectionBackoffIterator?
4444
var reconnect: Reconnect
4545
var candidate: Channel
46-
var readyChannelMuxPromise: EventLoopPromise<HTTP2StreamMultiplexer>
47-
var multiplexer: HTTP2StreamMultiplexer
46+
var readyChannelMuxPromise: EventLoopPromise<NIOHTTP2Handler.StreamMultiplexer>
47+
var multiplexer: NIOHTTP2Handler.StreamMultiplexer
4848
var error: Error?
4949

50-
init(from state: ConnectingState, candidate: Channel, multiplexer: HTTP2StreamMultiplexer) {
50+
init(
51+
from state: ConnectingState,
52+
candidate: Channel,
53+
multiplexer: NIOHTTP2Handler.StreamMultiplexer
54+
) {
5155
self.backoffIterator = state.backoffIterator
5256
self.reconnect = state.reconnect
5357
self.candidate = candidate
@@ -58,7 +62,7 @@ internal final class ConnectionManager: @unchecked Sendable {
5862

5963
internal struct ReadyState {
6064
var channel: Channel
61-
var multiplexer: HTTP2StreamMultiplexer
65+
var multiplexer: NIOHTTP2Handler.StreamMultiplexer
6266
var error: Error?
6367

6468
init(from state: ConnectedState) {
@@ -69,7 +73,7 @@ internal final class ConnectionManager: @unchecked Sendable {
6973

7074
internal struct TransientFailureState {
7175
var backoffIterator: ConnectionBackoffIterator?
72-
var readyChannelMuxPromise: EventLoopPromise<HTTP2StreamMultiplexer>
76+
var readyChannelMuxPromise: EventLoopPromise<NIOHTTP2Handler.StreamMultiplexer>
7377
var scheduled: Scheduled<Void>
7478
var reason: Error
7579

@@ -252,8 +256,8 @@ internal final class ConnectionManager: @unchecked Sendable {
252256
}
253257
}
254258

255-
/// Returns the `HTTP2StreamMultiplexer` from the 'ready' state or `nil` if it is not available.
256-
private var multiplexer: HTTP2StreamMultiplexer? {
259+
/// Returns the `NIOHTTP2Handler.StreamMultiplexer` from the 'ready' state or `nil` if it is not available.
260+
private var multiplexer: NIOHTTP2Handler.StreamMultiplexer? {
257261
self.eventLoop.assertInEventLoop()
258262
switch self.state {
259263
case let .ready(state):
@@ -361,8 +365,8 @@ internal final class ConnectionManager: @unchecked Sendable {
361365
/// Get the multiplexer from the underlying channel handling gRPC calls.
362366
/// if the `ConnectionManager` was configured to be `fastFailure` this will have
363367
/// one chance to connect - if not reconnections are managed here.
364-
internal func getHTTP2Multiplexer() -> EventLoopFuture<HTTP2StreamMultiplexer> {
365-
func getHTTP2Multiplexer0() -> EventLoopFuture<HTTP2StreamMultiplexer> {
368+
internal func getHTTP2Multiplexer() -> EventLoopFuture<NIOHTTP2Handler.StreamMultiplexer> {
369+
func getHTTP2Multiplexer0() -> EventLoopFuture<NIOHTTP2Handler.StreamMultiplexer> {
366370
switch self.callStartBehavior {
367371
case .waitsForConnectivity:
368372
return self.getHTTP2MultiplexerPatient()
@@ -382,8 +386,8 @@ internal final class ConnectionManager: @unchecked Sendable {
382386

383387
/// Returns a future for the multiplexer which succeeded when the channel is connected.
384388
/// Reconnects are handled if necessary.
385-
private func getHTTP2MultiplexerPatient() -> EventLoopFuture<HTTP2StreamMultiplexer> {
386-
let multiplexer: EventLoopFuture<HTTP2StreamMultiplexer>
389+
private func getHTTP2MultiplexerPatient() -> EventLoopFuture<NIOHTTP2Handler.StreamMultiplexer> {
390+
let multiplexer: EventLoopFuture<NIOHTTP2Handler.StreamMultiplexer>
387391

388392
switch self.state {
389393
case .idle:
@@ -421,11 +425,12 @@ internal final class ConnectionManager: @unchecked Sendable {
421425
/// attempt, or if the state is 'idle' returns the future for the next connection attempt.
422426
///
423427
/// Note: if the state is 'transientFailure' or 'shutdown' then a failed future will be returned.
424-
private func getHTTP2MultiplexerOptimistic() -> EventLoopFuture<HTTP2StreamMultiplexer> {
428+
private func getHTTP2MultiplexerOptimistic()
429+
-> EventLoopFuture<NIOHTTP2Handler.StreamMultiplexer> {
425430
// `getHTTP2Multiplexer` makes sure we're on the event loop but let's just be sure.
426431
self.eventLoop.preconditionInEventLoop()
427432

428-
let muxFuture: EventLoopFuture<HTTP2StreamMultiplexer> = { () in
433+
let muxFuture: EventLoopFuture<NIOHTTP2Handler.StreamMultiplexer> = { () in
429434
switch self.state {
430435
case .idle:
431436
self.startConnecting()
@@ -656,7 +661,7 @@ internal final class ConnectionManager: @unchecked Sendable {
656661
}
657662

658663
/// The connecting channel became `active`. Must be called on the `EventLoop`.
659-
internal func channelActive(channel: Channel, multiplexer: HTTP2StreamMultiplexer) {
664+
internal func channelActive(channel: Channel, multiplexer: NIOHTTP2Handler.StreamMultiplexer) {
660665
self.eventLoop.preconditionInEventLoop()
661666
self.logger.debug("activating connection", metadata: [
662667
"connectivity_state": "\(self.state.label)",
@@ -973,7 +978,7 @@ extension ConnectionManager {
973978

974979
private func startConnecting(
975980
backoffIterator: ConnectionBackoffIterator?,
976-
muxPromise: EventLoopPromise<HTTP2StreamMultiplexer>
981+
muxPromise: EventLoopPromise<NIOHTTP2Handler.StreamMultiplexer>
977982
) {
978983
let timeoutAndBackoff = backoffIterator?.next()
979984

@@ -1060,7 +1065,7 @@ extension ConnectionManager {
10601065

10611066
/// Returns the `multiplexer` from a connection in the `ready` state or `nil` if it is any
10621067
/// other state.
1063-
internal var multiplexer: HTTP2StreamMultiplexer? {
1068+
internal var multiplexer: NIOHTTP2Handler.StreamMultiplexer? {
10641069
return self.manager.multiplexer
10651070
}
10661071

Diff for: Sources/GRPC/ConnectionPool/ConnectionPool+PerConnectionState.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ extension ConnectionPool {
5353
}
5454

5555
@usableFromInline
56-
var multiplexer: HTTP2StreamMultiplexer
56+
var multiplexer: NIOHTTP2Handler.StreamMultiplexer
5757
/// Maximum number of available streams.
5858
@usableFromInline
5959
var maxAvailable: Int
@@ -73,7 +73,7 @@ extension ConnectionPool {
7373

7474
/// Increment the reserved streams and return the multiplexer.
7575
@usableFromInline
76-
mutating func reserve() -> HTTP2StreamMultiplexer {
76+
mutating func reserve() -> NIOHTTP2Handler.StreamMultiplexer {
7777
assert(!self.isQuiescing)
7878
self.reserved += 1
7979
return self.multiplexer
@@ -127,7 +127,7 @@ extension ConnectionPool {
127127
///
128128
/// The result may be safely unwrapped if `self.availableStreams > 0` when reserving a stream.
129129
@usableFromInline
130-
internal mutating func reserveStream() -> HTTP2StreamMultiplexer? {
130+
internal mutating func reserveStream() -> NIOHTTP2Handler.StreamMultiplexer? {
131131
return self._availability?.reserve()
132132
}
133133

Diff for: Sources/GRPC/ConnectionPool/ConnectionPool+Waiter.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ extension ConnectionPool {
3030

3131
/// The channel initializer.
3232
@usableFromInline
33-
internal let _channelInitializer: (Channel) -> EventLoopFuture<Void>
33+
internal let _channelInitializer: @Sendable (Channel) -> EventLoopFuture<Void>
3434

3535
/// The deadline at which the timeout is scheduled.
3636
@usableFromInline
@@ -51,7 +51,7 @@ extension ConnectionPool {
5151
internal init(
5252
deadline: NIODeadline,
5353
promise: EventLoopPromise<Channel>,
54-
channelInitializer: @escaping (Channel) -> EventLoopFuture<Void>
54+
channelInitializer: @escaping @Sendable (Channel) -> EventLoopFuture<Void>
5555
) {
5656
self._deadline = deadline
5757
self._promise = promise
@@ -83,7 +83,7 @@ extension ConnectionPool {
8383

8484
/// Succeed the waiter with the given multiplexer.
8585
@usableFromInline
86-
internal func succeed(with multiplexer: HTTP2StreamMultiplexer) {
86+
internal func succeed(with multiplexer: NIOHTTP2Handler.StreamMultiplexer) {
8787
self._scheduledTimeout?.cancel()
8888
self._scheduledTimeout = nil
8989
multiplexer.createStreamChannel(promise: self._promise, self._channelInitializer)

0 commit comments

Comments
 (0)