@@ -98,7 +98,9 @@ internal class StreamingResponseParts<Response> {
98
98
private let eventLoop : EventLoop
99
99
100
100
/// A callback for response messages.
101
- private let responseCallback : ( Response ) -> Void
101
+ private var responseCallback : ( Response ) -> Void
102
+
103
+ private static let noopCallback : ( Response ) -> Void = { _ in }
102
104
103
105
/// Lazy promises for the status, initial-, and trailing-metadata.
104
106
private var initialMetadataPromise : LazyEventLoopPromise < HPACKHeaders >
@@ -142,13 +144,23 @@ internal class StreamingResponseParts<Response> {
142
144
self . responseCallback ( response)
143
145
144
146
case let . end( status, trailers) :
147
+ // Once the stream has finished, we must release the callback, to make sure don't
148
+ // break potential retain cycles (the callback may reference other object's that in
149
+ // turn reference `StreamingResponseParts`).
150
+ self . responseCallback = Self . noopCallback
145
151
self . initialMetadataPromise. fail ( status)
146
152
self . trailingMetadataPromise. succeed ( trailers)
147
153
self . statusPromise. succeed ( status)
148
154
}
149
155
}
150
156
151
157
internal func handleError( _ error: Error ) {
158
+ self . eventLoop. assertInEventLoop ( )
159
+
160
+ // Once the stream has finished, we must release the callback, to make sure don't
161
+ // break potential retain cycles (the callback may reference other object's that in
162
+ // turn reference `StreamingResponseParts`).
163
+ self . responseCallback = Self . noopCallback
152
164
let withoutContext = error. removingContext ( )
153
165
let status = withoutContext. makeGRPCStatus ( )
154
166
self . initialMetadataPromise. fail ( withoutContext)
0 commit comments