@@ -310,6 +310,7 @@ internal final class EtcdHttpClient: @unchecked Sendable {
310310 private let config : DriverConnectionConfig
311311 private let lock = NSLock ( )
312312 private var session : URLSession ?
313+ private var sessionGeneration : UInt64 = 0
313314 private var currentTask : URLSessionDataTask ?
314315 private var authToken : String ?
315316 private var _isAuthenticating = false
@@ -408,6 +409,7 @@ internal final class EtcdHttpClient: @unchecked Sendable {
408409
409410 func disconnect( ) {
410411 lock. lock ( )
412+ sessionGeneration &+= 1
411413 currentTask? . cancel ( )
412414 currentTask = nil
413415 session? . invalidateAndCancel ( )
@@ -539,11 +541,12 @@ internal final class EtcdHttpClient: @unchecked Sendable {
539541
540542 func watch( key: String , prefix: Bool , timeout: TimeInterval ) async throws -> [ EtcdWatchEvent ] {
541543 lock. lock ( )
542- guard let session else {
544+ guard session != nil else {
543545 lock. unlock ( )
544546 throw EtcdError . notConnected
545547 }
546548 let token = authToken
549+ let generation = sessionGeneration
547550 lock. unlock ( )
548551
549552 let b64Key = Self . base64Encode ( key)
@@ -571,7 +574,13 @@ internal final class EtcdHttpClient: @unchecked Sendable {
571574
572575 group. addTask {
573576 let data : Data = try await withCheckedThrowingContinuation { continuation in
574- let task = session. dataTask ( with: request) { data, _, error in
577+ self . lock. lock ( )
578+ guard self . sessionGeneration == generation, let currentSession = self . session else {
579+ self . lock. unlock ( )
580+ continuation. resume ( throwing: EtcdError . notConnected)
581+ return
582+ }
583+ let task = currentSession. dataTask ( with: request) { data, _, error in
575584 if let error {
576585 // URLError.cancelled is expected when we cancel after timeout
577586 if ( error as? URLError ) ? . code == . cancelled {
@@ -583,7 +592,6 @@ internal final class EtcdHttpClient: @unchecked Sendable {
583592 }
584593 continuation. resume ( returning: data ?? Data ( ) )
585594 }
586- self . lock. lock ( )
587595 self . currentTask = task
588596 self . lock. unlock ( )
589597 collectedData. setTask ( task)
@@ -698,6 +706,7 @@ internal final class EtcdHttpClient: @unchecked Sendable {
698706 throw EtcdError . notConnected
699707 }
700708 let token = authToken
709+ let generation = sessionGeneration
701710 lock. unlock ( )
702711
703712 guard let url = URL ( string: " \( baseUrl) / \( path) " ) else {
@@ -714,7 +723,13 @@ internal final class EtcdHttpClient: @unchecked Sendable {
714723
715724 let ( data, response) = try await withTaskCancellationHandler {
716725 try await withCheckedThrowingContinuation { ( continuation: CheckedContinuation < ( Data , URLResponse ) , Error > ) in
717- let task = session. dataTask ( with: request) { data, response, error in
726+ self . lock. lock ( )
727+ guard self . sessionGeneration == generation, let currentSession = self . session else {
728+ self . lock. unlock ( )
729+ continuation. resume ( throwing: EtcdError . notConnected)
730+ return
731+ }
732+ let task = currentSession. dataTask ( with: request) { data, response, error in
718733 if let error {
719734 continuation. resume ( throwing: error)
720735 return
@@ -725,8 +740,6 @@ internal final class EtcdHttpClient: @unchecked Sendable {
725740 }
726741 continuation. resume ( returning: ( data, response) )
727742 }
728-
729- self . lock. lock ( )
730743 self . currentTask = task
731744 self . lock. unlock ( )
732745
@@ -806,15 +819,22 @@ internal final class EtcdHttpClient: @unchecked Sendable {
806819 request. httpBody = try JSONEncoder ( ) . encode ( authReq)
807820
808821 lock. lock ( )
809- guard let session else {
822+ guard session != nil else {
810823 lock. unlock ( )
811824 throw EtcdError . notConnected
812825 }
826+ let generation = sessionGeneration
813827 lock. unlock ( )
814828
815829 let ( data, response) = try await withCheckedThrowingContinuation {
816830 ( continuation: CheckedContinuation < ( Data , URLResponse ) , Error > ) in
817- let task = session. dataTask ( with: request) { data, response, error in
831+ self . lock. lock ( )
832+ guard self . sessionGeneration == generation, let currentSession = self . session else {
833+ self . lock. unlock ( )
834+ continuation. resume ( throwing: EtcdError . notConnected)
835+ return
836+ }
837+ let task = currentSession. dataTask ( with: request) { data, response, error in
818838 if let error {
819839 continuation. resume ( throwing: error)
820840 return
@@ -825,6 +845,7 @@ internal final class EtcdHttpClient: @unchecked Sendable {
825845 }
826846 continuation. resume ( returning: ( data, response) )
827847 }
848+ self . lock. unlock ( )
828849 task. resume ( )
829850 }
830851
0 commit comments