NSBackgroundActivityScheduler running too soon

I have an array of activities that need to be run at a specific time. The run in a background helper app. The array is sorted on date/time.

At 12:08:51 I add a new item in the array.. to run at 12:12. Upon creation the array is sorted again and the closest is added as an activity to a NSBackgroundActivityScheduler.

However it runs at creation and a few times more before 12:12. The next automation Normal doesn't run at creation as activity (activity Normal is already in the array of activities).

Why is this happening? And how can I fix it?


Log:
Code Block
12:08:34.272494+0200 Started Automation Activity
12:08:34.276633+0200 Next Automation Normal on 2021-04-15 08:50:00 +0000
12:08:51.550121+0200 Started Automation Activity
12:08:51.554565+0200 Next Automation Test1212 on 2021-04-14 10:12:00 +0000
12:08:51.755904+0200 Automation Test1212 is running
12:08:51.756135+0200 Changing to ID DFA4B3D5-3D6C-4F47-A740-7F8C2D6FB30D
12:08:57.040569+0200 Prepare for next automation
12:08:57.040641+0200 Stopped Automation Activity
12:08:57.040829+0200 Started Automation Activity
12:08:57.047549+0200 Next Automation Test1212 on 2021-04-14 10:12:00 +0000
12:09:04.400019+0200 Started Automation Activity
12:09:04.404916+0200 Next Automation Test1212 on 2021-04-14 10:12:00 +0000
12:10:29.600003+0200 Automation Test1212 is running
12:10:29.600073+0200 Changing to ID DFA4B3D5-3D6C-4F47-A740-7F8C2D6FB30D
12:10:35.269521+0200 Prepare for next automation
12:10:35.269598+0200 Stopped Automation Activity
12:10:35.269763+0200 Started Automation Activity
12:10:35.275532+0200 Next Automation Test1212 on 2021-04-14 10:12:00 +0000
12:11:20.557440+0200 Automation Test1212 is running
12:11:20.557496+0200 Changing to ID DFA4B3D5-3D6C-4F47-A740-7F8C2D6FB30D
12:11:26.154006+0200 Prepare for next automation
12:11:26.154087+0200 Stopped Automation Activity
12:11:26.154256+0200 Started Automation Activity
12:11:26.161030+0200 Next Automation Test1212 on 2021-04-14 10:12:00 +0000
12:12:10.062696+0200 Automation Test1212 is running
12:12:10.062803+0200 Changing to RuleSetID DFA4B3D5-3D6C-4F47-A740-7F8C2D6FB30D
12:12:15.658318+0200 Prepare for next automation
12:12:15.658471+0200 Stopped Automation Activity
12:12:15.658667+0200 Started Automation Activity
12:12:15.664819+0200 Next Automation Normal on 2021-04-15 08:50:00 +0000


Code:
Code Block
func nextAutomationFireDate() {
let moc = CoreDataStorage.shared.persistentContainer.viewContext
let automationDataRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "AutomationDB")
do {
var automations: [AutomationDB] = []
automations.removeAll()
// swiftlint:disable force_cast
automations = try moc.fetch(automationDataRequest) as! [AutomationDB]
let now = Date()
var automationItems: [AutomationStruct] = []
automationItems.removeAll()
// automations is an array from the users database... automationItems is an activity array. I cut this part because its not needed for the question
// Sort automations array on date
let sortedAutomationItems = automationItems.sorted(by: { (lhs, rhs) -> Bool in
return lhs.date < rhs.date
})
let nextAutomation = sortedAutomationItems[0]
let secondsBetweenNowAndNextAutomation = nextAutomation.date.timeIntervalSince(now)
self.log.content(category: "Background Task", message: "Next Automation \(nextAutomation.title) on \(nextAutomation.date)")
automationActivity.invalidate()
automationActivity.interval = secondsBetweenNowAndNextAutomation
automationActivity.repeats = false
automationActivity.qualityOfService = QualityOfService.userInitiated
automationActivity.schedule {(completion: NSBackgroundActivityScheduler.CompletionHandler) in
self.isBackgroundAutomationTaskRunning = true
self.log.content(category: "Background Task", message: "Automation \(nextAutomation.title) is running")
// do something
self.runAutomation(nextAutomation)
// schedule next fire date
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
NotificationCenter.default.post(name: .automationComplete, object: nil, userInfo: nil)
}
completion(NSBackgroundActivityScheduler.Result.finished)
}
} catch {
log.content(category: "Automations", message: "Failed to fetch AutomationDB items: \(error)")
}
}

Accepted Reply

NSBackgroundActivityScheduler is basically a wrapper around the XPC activity API <xpc/activity.h>. That header has a bunch of helpful info about the conceptual background to this API. And another great source of info is the WWDC presentations where the API was introduced:
Note The first video seems to have been lost )-: but the second one is still available (start around 40:00).

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Replies

NSBackgroundActivityScheduler is basically a wrapper around the XPC activity API <xpc/activity.h>. That header has a bunch of helpful info about the conceptual background to this API. And another great source of info is the WWDC presentations where the API was introduced:
Note The first video seems to have been lost )-: but the second one is still available (start around 40:00).

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"