How macOS schedules and dispatches background tasks using CTS 2

In the first article in this series, I explained how a great many background activities in macOS, including Time Machine backups, aren’t scheduled by the traditional Unix system cron, nor using launchd and its LaunchAgents and LaunchDaemons, but by a scheduling and dispatch system known as Centralized Task Scheduling (CTS), which uses Duet Activity Scheduler (DAS) to run activities when they’re most convenient to your Mac. This article goes further into CTS, providing you with a tool with which you can experiment with it, DispatchRider.

DispatchRider version 1.0b4 is available from here: dispatchrider10b4
As it’s a working experiment, I’m not adding it to a Product Page for the moment. It has fairly rudimentary documentation too, but as far as I’m aware does its job reliably. To follow this experiment youself, you’ll also need Mints version 1.0b9 or later, which provides easy access to log entries written by CTS and DAS.

dispatchrider01

DispatchRider provides you a way of running a command tool at regular intervals using CTS. Specify the command and any parameters or options, the frequency at which you want it run, its Quality of Service (priority), and any tolerance in minutes. To make this experiment simpler, it’s best to use a command tool such as my free blowhole, which simply writes a message to the unified log, at short intervals of a couple of minutes.

Set this up in its window, then click on Start. Watch that window, and each time the command is run, the number shown towards the bottom increments by one. You can then use the DAS Scheduling Log Window in Mints to inspect the log from just before you clicked that Start button for several minutes. You should see something like this.

When DispatchRider registers its new activity, it does so with CTS, marked by a log entry like
xpc_activity_register: co.eclecticlight.DispatchRider.tasks, criteria: dictionary
This shows that the new activity has been registered using a dictionary containing its settings. CTS then prints out its dictionary settings, after which it’s DAS’s turn to register the new activity using
Submitted Activity: 501:co.eclecticlight.DispatchRider.tasks:CF2474 at priority 5 with interval 120 <private>
This is assigned an ‘Optimal Score’ and a timer is set for its first run.

After a while, DAS will score this new activity to determine whether it should be run. You’ll see an entry similar to
'501:co.eclecticlight.DispatchRider.tasks:CF2474' CurrentScore: 0.974199, ThresholdScore: 0.461712 DecisionToRun:1

Shortly after that, CTS acknowledges the instruction from DAS:
DAS told us to run co.eclecticlight.DispatchRider.tasks
That triggers a ‘state change’ to reflect that CTS is about to run the activity:
Initiating XPC Activity: co.eclecticlight.DispatchRider.tasks
This is added to the power management state
taking power assertion: co.eclecticlight.DispatchRider.tasks: 41633

Once the activity is complete, CTS records
Completed XPC Activity: co.eclecticlight.DispatchRider.tasks
which is recorded by DAS:
COMPLETED 501:co.eclecticlight.DispatchRider.tasks:CF2474 at priority 5 <private>!

There follow two important log entries, in which CTS tells DAS to schedule the next run:
Rescheduling XPC Activity: co.eclecticlight.DispatchRider.tasks
Submitting DASActivity: <_DASActivity: "501:co.eclecticlight.DispatchRider.tasks:C3948D", Maintenance, 60s, [11/10/2020, 16:34:02 - 11/10/2020, 16:36:02], Group: "com.apple.dasd.default", Plugin Required, Interval=2, Budgeted, Delayed Start, User Specified: { }>

When you click on the Stop button, the activity is unregistered with CTS, in
_xpc_activity_unregister: co.eclecticlight.DispatchRider.tasks, 1, true
Its state is changed from 1 to -1, and cancelled with DAS:
CANCELED: 501:co.eclecticlight.DispatchRider.tasks:7BAEB3 at priority 5 <private>!

That completes the life cycle of a CTS activity.

DispatchRider is an experiment, and not intended to be a full background task manager. For over three years, I have been puzzled as to why so few third-party apps seem to use CTS, and why there’s no tool for users to add their own tasks for management by CTS. macOS seems to use it to great benefit, in spreading the load of background tasks, so that they are run when conditions are most suitable.

Is there any interest in having a proper background task manager which uses CTS – a tool to which you can add your own tasks?

In the next article in this series, I’ll look at how you can incorporate background tasks into your own apps, using the official interface to CTS, NSBackgroundActivityScheduler.