BGProcessingTaskRequest.earliestBeginDate prevents Task from being run

Hey,

I am having issues with the BGProcessingTaskRequest.earliestBeginDate property.

If I use this property, my tasks are never started. Even if I wait for 24hours, with screen off and plugged in.

In this example I use 15 Minutes from now:


class func schedule() {
        let request = BGProcessingTaskRequest(identifier: TASK_IDENTIFIER)
        request.requiresExternalPower = false
        request.requiresNetworkConnectivity = false
        request.earliestBeginDate = Date(timeIntervalSinceNow: 15*60)
        do {
            try BGTaskScheduler.shared.submit(request)
        } catch {
            print("Could not schedule task: \(error)")
        }
    }


But if I don’t set the property earliestBeginDate and keep it at nil, my task is run without problems.

I reproduces this 3 times and the task was run after 12 Minutes, 17Minutes and 12 Minutes.



One more question: What happens to my tasks if I reenter my App before the task was run? Will they be canceled or still run?


Sometimes I see following messages in the device syslog when I reenter the app before the task was run:

Jun 10 08:23:05 Tims-iPhone My App(DuetActivityScheduler)[4118] : Will expire BGTask activities: {(
)}
Jun 10 08:23:05 Tims-iPhone My App(BackgroundTasks)[4118] : Will expire activities: {(
)}
Jun 10 08:23:05 Tims-iPhone My App(BackgroundTasks)[4118] : Calling expiration handlers for activities: {(
)}
Jun 10 08:23:05 Tims-iPhone My App(BackgroundTasks)[4118] : Calling expiration handlers for tasks: {(
)}

My Task identifier is not present in this log messages, so I guess it is not affected?

Update:

If I set my phone to never deactivate it’s screen, the tasks will run in time, even if earliestBeginDate is used.

I scheduled the Task two times to run in 60 seconds and it needed 21Minutes and 12 Minutes to start.

Once I scheduled the task to run in 15 Minutes. This time it started after 19 Minutes.


So maybe this is working as intended. But it seems weird that the task are run only(preferably) if the screen is active.

The timing for BGProcessingTaskRequest can be complicated, since it deliberately tries to run your task when it "knows" (based on local usage patterns). In practice, that generally means "in the middle of the night" (~2am) while the user is asleep and the phone is charging.

Where this gets complicated is with a long delay like yours. Using 15 hours as an example, lets say you scheduled that task at 2pm, so the task would FIRST become eligible and 5am the next morning. In practice, it's very likely that the task WOULDN'T actually run then- the "tasks" for the day have already run (they ran earlier in the evening) and the scheduler tends to be conservative to try and avoid having to cancel in progress tasks.

Note that is also why you need to be careful about canceling and then rescheduling tasks. Extending the example above, if the user runs your app every day just before bed and you reschedule for 15 hours in the future, then it's very easy to end up with your processing tasks always scheduled for the "middle" of the day and never actually getting run.

Quick comment on this:

If I set my phone to never deactivate it’s screen, the tasks will run in time, even if earliestBeginDate is used.

This is basically an odd side effect of how all the scheduling logic works, not really intended behavior.

Kevin Elliott
DTS Engineer, CoreOS/Hardware
BGProcessingTaskRequest.earliestBeginDate prevents Task from being run
 
 
Q