@@ -71,17 +71,36 @@ extension TurnkeyContext {
7171 expTimestamp: TimeInterval ,
7272 buffer: TimeInterval = 5
7373 ) {
74+ // cancel any old timer
7475 expiryTasks [ sessionKey] ? . cancel ( )
75-
76- let now = DispatchTime . now ( )
77- let interval = max ( 0 , expTimestamp - Date( ) . timeIntervalSince1970 - buffer)
78- let deadline = now + . milliseconds( Int ( interval * 1_000 ) )
79-
76+
77+ let timeLeft = expTimestamp - Date( ) . timeIntervalSince1970
78+
79+ // if already within (or past) the buffer window, we just clear now
80+ if timeLeft <= buffer {
81+ clearSession ( for: sessionKey)
82+ return
83+ }
84+
85+ let interval = timeLeft - buffer
86+ let deadline = DispatchTime . now ( ) + . milliseconds( Int ( interval * 1_000 ) )
8087 let timer = DispatchSource . makeTimerSource ( )
88+
8189 timer. schedule ( deadline: deadline, leeway: . milliseconds( 100 ) )
8290 timer. setEventHandler { [ weak self] in
8391 guard let self = self else { return }
84-
92+
93+ // we calculate how much time is left when this handler actually runs
94+ // this is needed because if the app was backgrounded past the expiry,
95+ // the dispatch timer will still fire once the app returns to foreground
96+ // this avoids making a call we know will fail
97+ let currentLeft = expTimestamp - Date( ) . timeIntervalSince1970
98+ if currentLeft <= 0 {
99+ self . clearSession ( for: sessionKey)
100+ timer. cancel ( )
101+ return
102+ }
103+
85104 if let dur = AutoRefreshStore . durationSeconds ( for: sessionKey) {
86105 Task {
87106 do {
@@ -90,19 +109,21 @@ extension TurnkeyContext {
90109 sessionKey: sessionKey
91110 )
92111 } catch {
93- // refreshSession failed so we resort to clearing the session
94112 self . clearSession ( for: sessionKey)
95113 }
96114 }
97115 } else {
98116 self . clearSession ( for: sessionKey)
99117 }
118+
100119 timer. cancel ( )
101120 }
121+
102122 timer. resume ( )
103-
104123 expiryTasks [ sessionKey] = timer
105124 }
125+
126+
106127
107128 /// Persists all storage-level artefacts for a session, schedules its expiry
108129 /// timer, and (optionally) registers the session for auto-refresh.
0 commit comments