Add more safeguards to prevent RUNNINGBOARD 0xdead10cc crashes
This commit adds more safeguards to prevent RUNNINGBOARD 0xdead10cc crashes, by: 1. Using the `beginBackgroundTask(withName:expirationHandler:)` to request additional background execution time before completely suspending the app. See https://developer.apple.com/documentation/xcode/sigkill 2. Reorganizing app closing/cleanup tasks to be done in parallel when possible to decrease time needed to cleanup resources. Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit is contained in:
@@ -61,9 +61,18 @@ class NostrNetworkManager {
|
||||
}
|
||||
|
||||
func close() async {
|
||||
await self.reader.cancelAllTasks()
|
||||
await self.profilesManager.stop()
|
||||
pool.close()
|
||||
await withTaskGroup { group in
|
||||
// Spawn each cancellation task in parallel for faster execution speed
|
||||
group.addTask {
|
||||
await self.reader.cancelAllTasks()
|
||||
}
|
||||
group.addTask {
|
||||
await self.profilesManager.stop()
|
||||
}
|
||||
pool.close()
|
||||
// But await on each one to prevent race conditions
|
||||
for await value in group { continue }
|
||||
}
|
||||
}
|
||||
|
||||
func ping() {
|
||||
|
||||
@@ -42,6 +42,7 @@ extension NostrNetworkManager {
|
||||
try await Task.sleep(for: .seconds(1))
|
||||
try Task.checkCancellation()
|
||||
if subscriptionNeedsUpdate {
|
||||
try Task.checkCancellation()
|
||||
self.restartProfileListenerTask()
|
||||
subscriptionNeedsUpdate = false
|
||||
}
|
||||
@@ -50,10 +51,19 @@ extension NostrNetworkManager {
|
||||
}
|
||||
|
||||
func stop() async {
|
||||
self.subscriptionSwitcherTask?.cancel()
|
||||
self.profileListenerTask?.cancel()
|
||||
try? await self.subscriptionSwitcherTask?.value
|
||||
try? await self.profileListenerTask?.value
|
||||
await withTaskGroup { group in
|
||||
// Spawn each cancellation in parallel for better execution speed
|
||||
group.addTask {
|
||||
await self.subscriptionSwitcherTask?.cancel()
|
||||
try? await self.subscriptionSwitcherTask?.value
|
||||
}
|
||||
group.addTask {
|
||||
await self.profileListenerTask?.cancel()
|
||||
try? await self.profileListenerTask?.value
|
||||
}
|
||||
// But await for all of them to be done before returning to avoid race conditions
|
||||
for await value in group { continue }
|
||||
}
|
||||
}
|
||||
|
||||
private func restartProfileListenerTask() {
|
||||
@@ -70,6 +80,7 @@ extension NostrNetworkManager {
|
||||
let pubkeys = Array(streams.keys)
|
||||
guard pubkeys.count > 0 else { return }
|
||||
let profileFilter = NostrFilter(kinds: [.metadata], authors: pubkeys)
|
||||
try Task.checkCancellation()
|
||||
for await ndbLender in self.subscriptionManager.streamIndefinitely(filters: [profileFilter], streamMode: .ndbFirst) {
|
||||
try Task.checkCancellation()
|
||||
try? ndbLender.borrow { ev in
|
||||
|
||||
@@ -387,12 +387,21 @@ extension NostrNetworkManager {
|
||||
}
|
||||
|
||||
func cancelAllTasks() async {
|
||||
Log.info("Cancelling all SubscriptionManager tasks", for: .subscription_manager)
|
||||
for (taskId, _) in self.tasks {
|
||||
Log.info("Cancelling SubscriptionManager task %s", for: .subscription_manager, taskId.uuidString)
|
||||
await cancelAndCleanUp(taskId: taskId)
|
||||
await withTaskGroup { group in
|
||||
Log.info("Cancelling all SubscriptionManager tasks", for: .subscription_manager)
|
||||
// Start each task cancellation in parallel for faster execution
|
||||
for (taskId, _) in self.tasks {
|
||||
Log.info("Cancelling SubscriptionManager task %s", for: .subscription_manager, taskId.uuidString)
|
||||
group.addTask {
|
||||
await self.cancelAndCleanUp(taskId: taskId)
|
||||
}
|
||||
}
|
||||
// However, wait until all cancellations are complete to avoid race conditions.
|
||||
for await value in group {
|
||||
continue
|
||||
}
|
||||
Log.info("Cancelled all SubscriptionManager tasks", for: .subscription_manager)
|
||||
}
|
||||
Log.info("Cancelled all SubscriptionManager tasks", for: .subscription_manager)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user