feat(ios): Implement automatic app restart handling for KDF fatal errors#270
feat(ios): Implement automatic app restart handling for KDF fatal errors#270
Conversation
Implement automatic app restart mechanism for iOS when KDF encounters fatal transport errors or shutdown signals. This resolves issues where the app becomes unresponsive after KDF terminates unexpectedly. Changes: - Add KdfRestartHandler Swift plugin for iOS app restart via exit(0) - Add IosRestartHandler Dart wrapper with platform channel communication - Detect broken pipe errors (errno 32) and trigger iOS restart in KDF framework - Add shutdown signal handling to trigger restart via auth service - Improve event streaming service with configurable debug logging - Add retry logic for enabling shutdown stream after KDF startup - Enhance HTTP client error detection for fatal transport errors Technical Details: - iOS restart uses exit(0) requiring manual app reopen (iOS limitation) - Broken pipe detection covers errno 32, 54, 60, 61 socket errors - Single-flight health check pattern prevents concurrent checks - Event streaming service now logs event types and processing times Fixes app hangs after backgrounding and KDF termination on iOS.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughThis PR introduces a comprehensive event streaming infrastructure for real-time updates across multiple domains (balances, transactions, orderbook, network, shutdown signals), adds iOS restart handling, implements resource lifecycle management (dispose patterns) for repositories and providers, integrates NFT activation services, and adds caching/persistence layers for activated assets and pubkeys. Changes
Sequence Diagram(s)sequenceDiagram
participant App as Application
participant KDF as KdfEventStreamingService
participant Plat as Platform (Web/IO/Stub)
participant RPC as KomodoDefiRpcMethods
participant Worker as SharedWorker (Web)
App->>KDF: initialize()
KDF->>Plat: connectEventStream(onMessage)
alt Web Platform
Plat->>Worker: Create SharedWorker
Worker-->>Plat: Port connected
Plat->>Worker: port.start()
else IO Platform
Plat->>Plat: Establish SSE connection
end
RPC->>KDF: Enable stream (stream::balance::enable)
RPC-->>KDF: streamerId
loop Real-time events
Worker->>Plat: Broadcast message to all ports
Plat->>Plat: onMessage(eventData)
Plat->>KDF: Forward event
KDF->>KDF: Parse KdfEvent (fromJson)
KDF->>KDF: Route to typed stream (balanceEvents)
KDF-->>App: Emit BalanceEvent
end
App->>KDF: dispose()
KDF->>Plat: unsubscribe()
Plat->>RPC: stream::disable
sequenceDiagram
participant SDK as KomodoDefiSdk
participant Cache as ActivatedAssetsCache
participant Auth as KomodoDefiLocalAuth
participant RPC as ApiClient
participant Act as ActivationManager
SDK->>Cache: Create with TTL
Cache->>Auth: Subscribe to auth changes
loop Asset Activation Check
SDK->>Act: isAssetActive(assetId, forceRefresh: true)
Act->>Cache: getActivatedAssetIds(forceRefresh: true)
alt Cache valid and not forced
Cache-->>Act: Return cached assets
else Cache expired or forced refresh
Cache->>RPC: getEnabledCoins()
RPC-->>Cache: Enabled coins list
Cache->>Cache: Map to AssetId set
Cache->>Cache: Update cache + timestamp
Cache-->>Act: Return fresh assets
end
Act-->>SDK: true/false
end
Auth->>Cache: User signed out
Cache->>Cache: invalidate()
sequenceDiagram
participant App as Application
participant BM as BalanceManager
participant ESM as EventStreamingManager
participant Stream as Event Stream (balance_events)
participant Fallback as Polling
App->>BM: watchBalance(asset)
BM->>BM: Emit lastKnown balance (from cache)
alt Supports Balance Streaming
BM->>ESM: subscribeToBalance(coin)
ESM->>Stream: Enable stream
Stream->>Stream: Real-time updates
Stream-->>ESM: balanceEvent
ESM-->>BM: StreamSubscription
BM->>BM: Cache + emit balance
else Streaming unavailable
BM->>Fallback: Start polling
Fallback->>Fallback: Periodic RPC calls
end
App->>BM: dispose()
BM->>ESM: Cancel subscription
BM->>Fallback: Stop polling
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Areas requiring extra attention:
Possibly related issues
Possibly related PRs
Suggested labels
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull Request Overview
This PR implements real-time event streaming infrastructure for the Komodo DeFi Framework, significantly reducing RPC polling overhead and improving responsiveness across balance updates, transaction history, and other features.
Key changes:
- Adds Server-Sent Events (SSE) streaming on native platforms and SharedWorker-based streaming on Web
- Implements transaction history streaming with automatic fallback to polling when streaming is unavailable
- Adds balance event streaming with intelligent fallback mechanisms
- Introduces activated assets cache to reduce repeated
get_enabled_coinsRPC calls - Implements optimizations for new wallet creation to avoid unnecessary RPC spam
- Adds iOS app restart handling for KDF fatal errors and shutdown signals
Reviewed Changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
packages/komodo_defi_framework/lib/src/streaming/* |
New SSE/SharedWorker streaming infrastructure with platform-specific implementations |
packages/komodo_defi_sdk/lib/src/streaming/event_streaming_manager.dart |
High-level streaming manager with reference counting and lifecycle management |
packages/komodo_defi_sdk/lib/src/transaction_history/transaction_history_manager.dart |
Updated to use streaming with fallback to polling |
packages/komodo_defi_sdk/lib/src/balances/balance_manager.dart |
Updated to use balance streaming with stale-guard timers |
packages/komodo_defi_sdk/lib/src/assets/activated_assets_cache.dart |
New TTL-based cache for activated assets list |
packages/komodo_defi_local_auth/lib/src/auth/auth_service.dart |
Enhanced with shutdown signal streaming and improved health checks |
packages/komodo_defi_sdk/lib/src/transaction_history/transaction_storage.dart |
Fixed SplayTreeMap comparison to prevent stack overflow |
packages/komodo_wallet_cli/bin/update_api_config.dart |
Updated checksum replacement logic for API commit changes |
Comments suppressed due to low confidence (3)
packages/komodo_defi_local_auth/lib/src/auth/auth_service_operations_extension.dart:19
- The comment states 'Reduced from 5 minutes to 30 minutes' but the code shows
Duration(minutes: 5). The duration should be 30 minutes to match the comment, or the comment should be updated to reflect the actual 5-minute interval.
const Duration(minutes: 5),
packages/komodo_defi_local_auth/lib/src/auth/auth_service_operations_extension.dart:115
- [nitpick] The comment on line 114 says 'Bypass cached user' but the method name
_getActiveUser()is not visible in this diff. Consider adding a comment clarifying that this internal method bypasses the cache, or ensure the method name makes this clear.
final currentUser = await _getActiveUser();
packages/komodo_defi_framework/lib/src/streaming/event_streaming_platform_io.dart:48
- The RPC password is being passed in the HTTP header, but the comment on line 41-42 mentions KDF expects
?userpass=as a query parameter. This mismatch between comment and implementation could cause authentication issues if the header approach is incorrect.
'userpass': cfg.rpcPassword,
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
💡 Codex Reviewhttps://github.com/KomodoPlatform/komodo-defi-sdk-flutter/blob/67f6e5034f088c234065d4f2ff7c7feccb05793f/packages/komodo_defi_framework/lib/src/streaming/event_streaming_platform_io.dart#L88-L92 The IO implementation declares https://github.com/KomodoPlatform/komodo-defi-sdk-flutter/blob/67f6e5034f088c234065d4f2ff7c7feccb05793f/packages/komodo_defi_framework/lib/src/streaming/event_streaming_platform_io.dart#L12-L18 The SSE URL produced in ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
Visit the preview URL for this PR (updated for commit 5e43e83): https://komodo-playground--pr270-feat-ios-crash-resta-j0m0gunn.web.app (expires Thu, 06 Nov 2025 15:13:32 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 Sign: 2bfedd77fdea45b25ba7c784416e81f177aa5c47 |
|
Visit the preview URL for this PR (updated for commit 5e43e83): https://kdf-sdk--pr270-feat-ios-crash-resta-6kvskll4.web.app (expires Thu, 06 Nov 2025 15:11:35 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 Sign: 9c1b6e6c010cf0b965c455ba7a69c4aedafa8a1d |
Move streaming logging to the main logger so that it shows in the log storage.
…dk-flutter into feat/ios-crash-restart
Overview
This PR implements an automatic app restart mechanism for iOS when the Komodo DeFi Framework (KDF) encounters fatal transport errors or receives a shutdown signal. This resolves a critical issue where the app becomes unresponsive after KDF terminates unexpectedly, particularly after backgrounding on iOS.
Problem Statement
On iOS, when KDF terminates unexpectedly (e.g., due to memory pressure during backgrounding), the app often experiences:
Solution
Implement native iOS restart handling with intelligent error detection:
Native iOS Plugin (
KdfRestartHandler.swift)exit(0)(requires manual user reopen due to iOS limitations)Dart Platform Interface (
ios_restart_handler.dart)Error Detection in KDF Framework
Shutdown Signal Handling
Enhanced Event Streaming
Technical Details
Testing Notes
Related Issues
Fixes issues related to iOS app hangs after backgrounding and KDF termination.
Summary by CodeRabbit
Note
Implements an iOS restart mechanism (native + Dart) triggered on fatal transport errors and shutdown signals, with improved streaming/logging and auth health-check handling.
KdfRestartHandlerplugin and register viaKomodoDefiFrameworkPlugin.IosRestartHandler(method channelcom.komodoplatform.kdf/restart).KomodoDefiFramework, detect fatal socket errors (EPIPE/32, etc.), reset HTTP client, and on iOS request app restart; exposehandleShutdownSignalForRestart.shutdownSignals; emit sign-out immediately and trigger iOS restart.KdfEventStreamingService: debug logging toggle, event processing timing, verbose payload logs, anddispose()wiring in framework.Written by Cursor Bugbot for commit 5e43e83. This will update automatically on new commits. Configure here.