Browse Source

avoid simultaneous background fetches, resulting in startIo/maybeNetwork/stopIo being double-called

B. Petersen 4 years ago
parent
commit
e2fc6f661f
2 changed files with 31 additions and 4 deletions
  1. 23 0
      deltachat-ios/AppDelegate.swift
  2. 8 4
      deltachat-ios/Controller/SettingsController.swift

+ 23 - 0
deltachat-ios/AppDelegate.swift

@@ -20,6 +20,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     var window: UIWindow?
     var notifyToken: String?
 
+    // `bgIoTimestamp` is set to last enter-background or last remote- or local-wakeup.
+    // in the minute after these events, subsequent remote- or local-wakeups are skipped -
+    // in favor to the chance of being awakened when it makes more sense
+    // and to avoid issues with calling concurrent series of startIo/maybeNetwork/stopIo.
+    var bgIoTimestamp: Double = 0.0
+
 
     // MARK: - app main entry point
 
@@ -167,6 +173,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     // eg. to complete sending messages out and to react to responses.
     private func registerBackgroundTask() {
         logger.info("⬅️ registering background task")
+        bgIoTimestamp = Double(Date().timeIntervalSince1970)
         backgroundTask = UIApplication.shared.beginBackgroundTask { [weak self] in
             // usually, the background thread is finished before in maybeStop()
             logger.info("⬅️ background expirationHandler called")
@@ -341,6 +348,22 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
             return
         }
 
+        // from time to time, `didReceiveRemoteNotification` and `performFetchWithCompletionHandler`
+        // are actually called at the same millisecond.
+        //
+        // therefore, if last fetch is less than a minute ago, we skip this call;
+        // this also lets the completionHandler being called earlier so that we maybe get awakened when it makes more sense.
+        //
+        // nb: calling the completion handler with .noData results in less calls overall.
+        // if at some point we do per-message-push-notifications, we need to tweak this gate.
+        let nowTimestamp = Double(Date().timeIntervalSince1970)
+        if nowTimestamp < bgIoTimestamp + 60 {
+            logger.info("➡️ fetch was just executed, skipping")
+            completionHandler(.newData)
+            return
+        }
+        bgIoTimestamp = nowTimestamp
+
         // we're in background, run IO for a little time
         dcContext.maybeStartIo()
         dcContext.maybeNetwork()

+ 8 - 4
deltachat-ios/Controller/SettingsController.swift

@@ -477,17 +477,21 @@ internal final class SettingsViewController: UITableViewController, ProgressAler
         for name in ["notify-remote-launch", "notify-remote-receive", "notify-local-wakeup"] {
             let cnt = UserDefaults.standard.integer(forKey: name + "-count")
 
-            let startInt = UserDefaults.standard.double(forKey: name + "-start")
-            let startStr = startInt==0.0 ? "" : " since " + DateUtils.getExtendedRelativeTimeSpanString(timeStamp: startInt)
+            let startDbl = UserDefaults.standard.double(forKey: name + "-start")
+            let startStr = startDbl==0.0 ? "" : " since " + DateUtils.getExtendedRelativeTimeSpanString(timeStamp: startDbl)
 
-            let timestampInt = UserDefaults.standard.double(forKey: name + "-last")
-            let timestampStr = timestampInt==0.0 ? "" : ", last " + DateUtils.getExtendedRelativeTimeSpanString(timeStamp: timestampInt)
+            let timestampDbl = UserDefaults.standard.double(forKey: name + "-last")
+            let timestampStr = timestampDbl==0.0 ? "" : ", last " + DateUtils.getExtendedRelativeTimeSpanString(timeStamp: timestampDbl)
 
             info += "\(name)=\(cnt)x\(startStr)\(timestampStr)\n"
         }
 
         if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
             info += "notify-token=\(appDelegate.notifyToken ?? "<unset>")\n"
+
+            let timestampDbl = appDelegate.bgIoTimestamp
+            let timestampStr = timestampDbl==0.0 ? "<unset>" : DateUtils.getExtendedRelativeTimeSpanString(timeStamp: timestampDbl)
+            info += "last-bg-io=\(timestampStr)\n"
         }
 
         #if DEBUG