Skip to content

Commit b5b8bbf

Browse files
Fix/auth retry 384 (#387)
* fix(core): retry HTTP/auth on reconnect after offline init (#384) PR #381 fixed offline model discovery by catching setupHTTP errors, but hasCompletedServicesInit was still set to true, permanently locking the SDK in offline mode for the session. Introduce a separate hasCompletedHTTPSetup flag to track HTTP/auth status independently from core services initialization. When ensureServicesReady() detects that core init is done but HTTP is not, it calls retryHTTPSetup() to attempt authentication again. This allows the SDK to recover automatically when connectivity returns. Also fixes stale telemetry comment that claimed HTTP was configured when it may not have been (offline path). * fix(core): add auth retry mechanism for offline-to-online transitions (#384) After PR #381, the SDK could initialize offline but hasCompletedServicesInit was set to true, permanently locking out HTTP/auth retries for the session. Introduce a separate hasCompletedHTTPSetup flag to track HTTP/auth status independently from core services initialization. ensureServicesReady() now detects when core init succeeded but HTTP failed, and calls retryHTTPSetup() to attempt auth again — enabling seamless offline-to-online transitions. Changes: - Add hasCompletedHTTPSetup flag (set only on setupHTTP success) - Modify ensureServicesReady() to retry HTTP when core is done but auth isn't - Add retryHTTPSetup() helper (idempotent, failures silently logged) - Fix stale telemetry comment to reflect offline-mode possibility - Reset hasCompletedHTTPSetup in reset() for clean test state * refactor(core): address CodeRabbit feedback on auth retry PR - Update completeServicesInitialization() docstring to clarify that its fast-path bypasses HTTP retry (handled by ensureServicesReady()) - Remove unnecessary throws from retryHTTPSetup() since errors are caught internally and never propagate
1 parent ac41467 commit b5b8bbf

1 file changed

Lines changed: 46 additions & 7 deletions

File tree

sdk/runanywhere-swift/Sources/RunAnywhere/Public/RunAnywhere.swift

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ public enum RunAnywhere {
6565

6666
/// Track if services initialization is complete (makes API calls O(1) after first use)
6767
internal static var hasCompletedServicesInit = false
68+
/// Track if HTTP/auth setup succeeded (separate from core services so auth can be retried on reconnect)
69+
internal static var hasCompletedHTTPSetup = false
6870

6971
// MARK: - SDK State
7072

@@ -140,6 +142,7 @@ public enum RunAnywhere {
140142

141143
isInitialized = false
142144
hasCompletedServicesInit = false
145+
hasCompletedHTTPSetup = false
143146
initParams = nil
144147
currentEnvironment = nil
145148

@@ -293,7 +296,10 @@ public enum RunAnywhere {
293296
/// Complete services initialization (Phase 2)
294297
///
295298
/// Called automatically in background by `initialize()`, or can be awaited directly
296-
/// via `initializeAsync()`. Safe to call multiple times - returns immediately if already done.
299+
/// via `initializeAsync()`. Safe to call multiple times — returns immediately if Phase 2
300+
/// is already complete. Note: if initialization succeeded in offline mode (HTTP/auth setup
301+
/// failed), this fast-path still returns immediately. HTTP/auth retry is handled
302+
/// automatically by `ensureServicesReady()` on the next API call.
297303
///
298304
/// This method:
299305
/// 1. Sets up API client (with authentication for production/staging)
@@ -321,17 +327,17 @@ public enum RunAnywhere {
321327
// Step 1: Configure HTTP transport
322328
do {
323329
try await setupHTTP(params: params, environment: environment, logger: logger)
330+
hasCompletedHTTPSetup = true
324331
} catch {
325332
// If HTTP/auth setup fails (e.g. device is offline), log warning but
326333
// continue initialization so local/cached models remain accessible.
327334
logger.warning("⚠️ HTTP/Auth setup failed (offline?): \(error.localizedDescription)")
328335
logger.info("Continuing SDK init in offline mode – local models will be available")
329336
}
330337

331-
// Step 1.5: Flush any queued telemetry events now that HTTP is configured
332-
// This ensures events queued during initialization are sent
338+
// Step 1.5: Flush any queued telemetry events (may be no-op if HTTP unconfigured)
333339
CppBridge.Telemetry.flush()
334-
logger.debug("Flushed queued telemetry events after HTTP configuration")
340+
logger.debug("Attempted telemetry flush (may be no-op if HTTP unconfigured)")
335341
}
336342

337343
// Step 2: Initialize C++ state
@@ -376,14 +382,47 @@ public enum RunAnywhere {
376382
}
377383

378384
/// Ensure services are ready before API calls (internal guard)
379-
/// O(1) after first successful initialization
385+
/// O(1) after first successful initialization with HTTP configured.
386+
/// If core services are done but HTTP/auth failed (offline init), retries auth only.
380387
internal static func ensureServicesReady() async throws {
381-
if hasCompletedServicesInit {
382-
return // O(1) fast path
388+
if hasCompletedServicesInit && hasCompletedHTTPSetup {
389+
return // O(1) fast path — fully initialized
390+
}
391+
if hasCompletedServicesInit && !hasCompletedHTTPSetup {
392+
// Core services done, but HTTP/auth failed earlier (offline init).
393+
// Retry HTTP setup only — safe because setupHTTP is idempotent.
394+
await retryHTTPSetup()
395+
return
383396
}
384397
try await completeServicesInitialization()
385398
}
386399

400+
/// Retry HTTP/auth setup after an offline initialization.
401+
/// Safe to call multiple times — checks `CppBridge.HTTP.shared.isConfigured` first.
402+
/// Failures are silently logged; the next `ensureServicesReady()` call will retry.
403+
private static func retryHTTPSetup() async {
404+
guard let params = initParams, let environment = currentEnvironment else { return }
405+
let logger = SDKLogger(category: "RunAnywhere.HTTPRetry")
406+
407+
let httpNeedsInit = await !CppBridge.HTTP.shared.isConfigured
408+
guard httpNeedsInit else {
409+
hasCompletedHTTPSetup = true
410+
return
411+
}
412+
413+
do {
414+
try await setupHTTP(params: params, environment: environment, logger: logger)
415+
hasCompletedHTTPSetup = true
416+
logger.info("✅ HTTP/Auth setup succeeded on retry")
417+
418+
// Flush any telemetry events queued during offline period
419+
CppBridge.Telemetry.flush()
420+
logger.debug("Flushed queued telemetry after successful HTTP retry")
421+
} catch {
422+
logger.debug("HTTP/Auth retry failed (still offline?): \(error.localizedDescription)")
423+
}
424+
}
425+
387426
// ═══════════════════════════════════════════════════════════════════════════
388427
// MARK: - Private: Service Setup Helpers
389428
// ═══════════════════════════════════════════════════════════════════════════

0 commit comments

Comments
 (0)