Skip to content

Commit 96c3077

Browse files
authored
WebSocket leak (#760)
Resolves #759 Root cause: `URLSession(configuration: config, delegate: self, delegateQueue: nil)` keeps a strong [reference](https://developer.apple.com/documentation/foundation/urlsession/init(configuration:delegate:delegatequeue:)) to its delegate
1 parent ec2377c commit 96c3077

File tree

4 files changed

+19
-0
lines changed

4 files changed

+19
-0
lines changed

.changes/socket-leak

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
patch type="fixed" "Fixed WebSocket memory leak after disconnecting"

Sources/LiveKit/Support/WebSocket.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ final class WebSocket: NSObject, @unchecked Sendable, Loggable, AsyncSequence, U
8484

8585
func close() {
8686
task.cancel(with: .normalClosure, reason: nil)
87+
urlSession.finishTasksAndInvalidate()
8788

8889
_state.mutate { state in
8990
state.connectContinuation?.resume(throwing: LiveKitError(.cancelled))

Tests/LiveKitTests/Room/RoomTests.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ class RoomTests: LKTestCase, @unchecked Sendable {
4141
}
4242
}
4343

44+
func testResourcesCleanUp() async throws {
45+
try await withRooms([RoomTestingOptions()]) { rooms in
46+
let room = rooms[0]
47+
48+
let socket = await room.signalClient._state.socket
49+
self.noLeaks(of: socket!)
50+
}
51+
}
52+
4453
func testSendDataPacket() async throws {
4554
try await withRooms([RoomTestingOptions()]) { rooms in
4655
let room = rooms[0]

Tests/LiveKitTests/Support/Assertions.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,11 @@ func XCTAssertThrowsErrorAsync(_ expression: @autoclosure () async throws -> som
2424
// Pass
2525
}
2626
}
27+
28+
extension LKTestCase {
29+
func noLeaks(of instance: AnyObject & Sendable, file: StaticString = #filePath, line: UInt = #line) {
30+
addTeardownBlock { [weak instance] in
31+
XCTAssertNil(instance, "Leaked object: \(String(describing: instance))", file: file, line: line)
32+
}
33+
}
34+
}

0 commit comments

Comments
 (0)