Skip to content
AB

Resumable One-Year HealthKit Backfills

Import long health histories in bounded windows with durable progress and idempotent writes.

Ashish BhakhandPublished

A one-year import cannot assume the app remains active, the network stays available, or every HealthKit query succeeds.

Process history in small date windows and persist progress after each complete window:

Code
struct BackfillProgress: Codable {
    var oldestCompletedDay: Date?
    var targetOldestDay: Date
    var status: Status
}

Query, normalize, save locally, upload idempotently, and only then advance oldestCompletedDay. If the app stops after the server commits but before progress updates, the same window is sent again safely.

Use semantic identities for daily aggregates and stable source identifiers for events. Device-local database IDs must not define server identity across reinstalls.

Cancellation should finish the current atomic step and leave resumable state. Do not hold one SwiftData transaction or giant in-memory array for the whole year.

Expose progress without promising an exact completion time. HealthKit volume varies widely by device and user history.

Test interruption at every boundary, overlapping windows, no-data days, reinstalls, and two devices importing the same dates. Backfill becomes dependable when repetition repairs state instead of duplicating it.

← Back to all writing