How macOS schedules and dispatches background tasks using CTS 1

In most traditional Unix-family operating systems, running a task every hour, day, or week is accomplished using cron and configured using a crontab, a scheduling table which could, for example, be used to run Time Machine’s timed backups. Although Mac OS X and now macOS have retained support for cron and crontab, they have long been deprecated in favour of launchd, which is the most important process running in macOS after the kernel itself.

Using launchd isn’t difficult, and a matter of setting up a property list in one of the LaunchAgents or LaunchDaemons folders, following the instructions detailed in Apple’s guide. There are plenty of tools to help you do this, from Peter Borg’s generic Lingon to specialist apps which use this to customise Time Machine backup scheduling.

Much older versions of macOS have suffered problems with this system (and with cron), but many Apple and third-party products now put their trust in launchd working, and it very seldom disappoints.

Some time after 2011, it appears that Apple started moving its own scheduled and background services, like Time Machine backup, to use a novel dispatching system involving two services, Duet Activity Scheduler (DAS) and Centralized Task Scheduling (CTS), the latter being intimately related or a part of the lightweight communication and dispatching system XPC. No one outside Apple seems to know when this happened, as DAS and CTS are almost completely undocumented.

By Sierra’s release, the DAS and CTS dispatching system managed more than seventy activities at most times, one of which is Time Machine’s scheduled backups. However, in Sierra this system has a bug which results in its breakdown: backups suddenly become irregular or stop altogether, and the other activities also become unreliable. That was fixed in High Sierra.

Among the heaviest users of CTS in Catalina (on my desktop iMac Pro, at least) are the following:

  • com.apple.accounts.cleanup
  • com.apple.AddressBook.ScheduledSync – Contacts syncing
  • com.apple.backupd-auto – Time Machine automatic backups
  • com.apple.bird.stage.gc – iCloud
  • com.apple.calendar.AlarmScan – Calendar event warnings
  • com.apple.cloudkit.assetHandleExpiration – iCloud
  • com.apple.CoreAnalytics.Daily
  • com.apple.coreduetd.people
  • com.apple.FileProvider.cache-delete.push – cache maintenance
  • com.apple.HMFoundation.Message.Dispatcher.Index
  • com.apple.ical.sync.x-coredata://C3502861-F6AE-44DA-AAE8-9318B23D56A7/CalDAVPrincipal/p5 – Calendar syncing
  • com.apple.knowledgestore.sync
  • com.apple.mds.Health check (2).0
  • com.apple.mediaanalysisd.fullanalysis
  • com.apple.mediaanalysisd.photosanalysis – Photos library image analysis
  • com.apple.messages.messageSyncing – Messages syncing
  • com.apple.parsec-fbf.flush
  • com.apple.photoanalysisd.backgroundanalysis – Photos library image analysis
  • com.apple.photolibraryd.curatedlibraryprocessing
  • com.apple.routined.locationAwareness.heartbeat
  • com.apple.Safari.SafeBrowsing.BrowsingDatabases.Update – Safari Safe Browsing updates
  • com.apple.SafariShared.WBSPeriodicActivityScheduler
  • com.apple.searchd.expirations
  • com.apple.suggestd.persist-stats
  • com.apple.suggestions.harvest
  • com.apple.syncdefaultsd
  • com.apple.timed.ntp.wanted – checking and setting the clock.

You’ll notice that not one of those listed is a third-party service, despite the fact that Apple provides a developer interface to CTS which is quite easy to use. As far as I’m aware, though, the user can’t schedule their own tools or scripts to be run by CTS, in the way we can with launchd.

CTS aims to ‘intelligently’ decide when to perform its tasks, according to provided criteria. It’s typically used for background tasks which need to be performed repeatedly, where the exact interval between runs isn’t critical. Time Machine backups are a good example: they don’t need to be run at precisely one hour intervals, so CTS can decide the best time, according to energy usage, thermal conditions, and loading on the processor cores.

Background tasks which are registered with CTS are in fact scheduled by a different subsystem, DAS. This maintains lists of activities, with their priorities and the time that each is next due to be run. It periodically re-computes a priority score for each, on a scale from 0 to 1, and compares those against a threshold. Activities which are due and exceed the threshold are then dispatched for execution by CTS.

CTS records in the unified log when it has been instructed to run an activity by DAS in a distinctive entry beginning DAS told us to run. If you have a copy of Mints version 1.0b9, you can see these by obtaining a log excerpt for DAS scheduling covering the last ten minutes or so. Once CTS has been told to run an activity, it does so using XPC, a lightweight cross-process communication system, rather than using launchd.

The dialog between DAS and CTS resumes once the activity is complete, which is reported back to CTS by XPC. CTS closes its connection with the completed activity, and schedules the next run with DAS, which adds that to a list of activities.

The bug in Sierra is severe, and renders DAS incapable of dispatching activities reliably. CTS works fine for the first few days of continuous running, then DAS – presumably affected by a memory leak or failure to maintain its activity lists – falls apart. Instead of performing its frequent reassessments of activities and their priority scores, it runs intermittently, and may forget to dispatch a scheduled backup for several hours.

In the next article in this series, I’ll provide you with a utility which can use CTS to schedule your own activities, and combining that with Mints, I’ll walk through how CTS works in detail.