Complication not updating after 5 days

I have developed a Watch app that features a complication.
It updates every minute and runs happily for 5 or 6 days, then stops updating. I.e. getTimelineEntries stops being called. 
I have tried to replicate the issue using the simulator but it updates without problems.

The app tells the time in German and update the complication every minute.

I have created: FB9007754 which contains the source code and sysdiagnose log.
Answered by alisdair_little in 669701022
I got some assistance from an Apple engineer and have solved the issue.

The key step is to call CLKComplicationServer.reloadTimeline(for:) as part of a background update. In my case every 6 hours.

class ExtensionDelegate: NSObject, WKExtensionDelegate {
    func applicationDidFinishLaunching() {
        scheduleBackgroundRefreshTasks()
    }

    func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
        for task in backgroundTasks {
            switch task {
            case let backgroundTask as WKApplicationRefreshBackgroundTask:
                let complicationServer = CLKComplicationServer.sharedInstance()
                for complication in complicationServer.activeComplications! {
                    complicationServer.reloadTimeline(for: complication)
                }
                self.scheduleBackgroundRefreshTasks()
                backgroundTask.setTaskCompletedWithSnapshot(true)
            case let snapshotTask as WKSnapshotRefreshBackgroundTask:
                snapshotTask.setTaskCompleted(restoredDefaultState: true, estimatedSnapshotExpiration: Date.distantFuture, userInfo: nil)
            case let connectivityTask as WKWatchConnectivityRefreshBackgroundTask:
                connectivityTask.setTaskCompletedWithSnapshot(false)
            case let urlSessionTask as WKURLSessionRefreshBackgroundTask:
                urlSessionTask.setTaskCompletedWithSnapshot(false)
            case let relevantShortcutTask as WKRelevantShortcutRefreshBackgroundTask:
                relevantShortcutTask.setTaskCompletedWithSnapshot(false)
            case let intentDidRunTask as WKIntentDidRunRefreshBackgroundTask:
                intentDidRunTask.setTaskCompletedWithSnapshot(false)
            default:
                task.setTaskCompletedWithSnapshot(false)
            }
        }
    }

    func scheduleBackgroundRefreshTasks() {
        let watchExtension = WKExtension.shared()
        let targetDate = Date().addingTimeInterval(360.0 * 60.0)
        watchExtension.scheduleBackgroundRefresh(withPreferredDate: targetDate, userInfo: nil) { (error) in
            if let error = error {
                print("* An background refresh error occurred: \(error.localizedDescription) *")
                return
            }
            print("* scheduleBackgroundRefreshTasks \(targetDate) *")
        }
    }
}

In case you are having trouble having your extension delegate add this line to your ...App.swift file.
    @WKExtensionDelegateAdaptor(ExtensionDelegate.self) var appDelegate
Complications cannot update every minute—your app does not get enough runtime for that. Plan to get about 4 updates an *hour*, not an update every minute. Also, this question sounds very familiar... did you not start a thread about this already?
Apologies, I started a new Post as I accidentally clicked Resolved on the old one.

Using the official sample, Coffee Tracker, it provides timeline entries every 5 minutes.
My app is doing the same thing every 1 minute and works fine for 5 days.

It does not use background updates (maximum 4 per hour), just timeline entries.

    // Return future timeline entries.
    func getTimelineEntries(for complication: CLKComplication,
                            after date: Date,
                            limit: Int,
                            withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Void) {
        let fiveMinutes = 5.0 * 60.0
        let twentyFourHours = 24.0 * 60.0 * 60.0

        // Create an array to hold the timeline entries.
        var entries = [CLKComplicationTimelineEntry]()

        // Calculate the start and end dates.
        var current = date.addingTimeInterval(fiveMinutes)
        let endDate = date.addingTimeInterval(twentyFourHours)

        // Create a timeline entry for every five minutes from the starting time.
        // Stop once you reach the limit or the end date.
        while (current.compare(endDate) == .orderedAscending) && (entries.count < limit) {
            entries.append(createTimelineEntry(forComplication: complication, date: current))
            current = current.addingTimeInterval(fiveMinutes)
        }
        handler(entries)
    }
From the documentation getTimelineEntries should work. It is only called once every 24 hours and creates an array of entries.

It says that: If two entries are less than one minute apart, ClockKit discards one of the entries.
I'm having a similar or identical issue for another time based complication: an assistive device for people with circadian rhythm disorders. I've resorted to reducing the timeline entries to 10 per hour; but the app eventually stops updating the timeline even with this decrease in regularity.

I don't see where the documentation says that getTimelineEntries is only called once every 24 hours. Can you post a link to or exact quote from the documentation?

My current test is installing the complication compiled as a release, rather than debug, build. Have you tried that yourself yet?
I find that there are no issues when running on the simulator but on the device it stops updating.
I have now raised a Code Level Support Ticket so will update this discussion if I get any news.

When you create timeline entries you specify a start and end date, for me I have used 24 hours (as in Apples sample) but I guess this could be changed.

The engineer seemed to suggest that the watch could update 4 times per hour, so you could try updating every hour to be safe.

        // Calculate the start and end dates.
        var current = date.addingTimeInterval(minute)
        let endDate = date.addingTimeInterval(24.0 * 60.0 * 60.0)

        while (current.compare(endDate) == .orderedAscending) && (entries.count < limit) {
            if let timeline = createTimelineEntry(complication: complication, forDate: current) {
                entries.append(timeline)
            }
            current = current.addingTimeInterval(minute)
        }
Accepted Answer
I got some assistance from an Apple engineer and have solved the issue.

The key step is to call CLKComplicationServer.reloadTimeline(for:) as part of a background update. In my case every 6 hours.

class ExtensionDelegate: NSObject, WKExtensionDelegate {
    func applicationDidFinishLaunching() {
        scheduleBackgroundRefreshTasks()
    }

    func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
        for task in backgroundTasks {
            switch task {
            case let backgroundTask as WKApplicationRefreshBackgroundTask:
                let complicationServer = CLKComplicationServer.sharedInstance()
                for complication in complicationServer.activeComplications! {
                    complicationServer.reloadTimeline(for: complication)
                }
                self.scheduleBackgroundRefreshTasks()
                backgroundTask.setTaskCompletedWithSnapshot(true)
            case let snapshotTask as WKSnapshotRefreshBackgroundTask:
                snapshotTask.setTaskCompleted(restoredDefaultState: true, estimatedSnapshotExpiration: Date.distantFuture, userInfo: nil)
            case let connectivityTask as WKWatchConnectivityRefreshBackgroundTask:
                connectivityTask.setTaskCompletedWithSnapshot(false)
            case let urlSessionTask as WKURLSessionRefreshBackgroundTask:
                urlSessionTask.setTaskCompletedWithSnapshot(false)
            case let relevantShortcutTask as WKRelevantShortcutRefreshBackgroundTask:
                relevantShortcutTask.setTaskCompletedWithSnapshot(false)
            case let intentDidRunTask as WKIntentDidRunRefreshBackgroundTask:
                intentDidRunTask.setTaskCompletedWithSnapshot(false)
            default:
                task.setTaskCompletedWithSnapshot(false)
            }
        }
    }

    func scheduleBackgroundRefreshTasks() {
        let watchExtension = WKExtension.shared()
        let targetDate = Date().addingTimeInterval(360.0 * 60.0)
        watchExtension.scheduleBackgroundRefresh(withPreferredDate: targetDate, userInfo: nil) { (error) in
            if let error = error {
                print("* An background refresh error occurred: \(error.localizedDescription) *")
                return
            }
            print("* scheduleBackgroundRefreshTasks \(targetDate) *")
        }
    }
}

In case you are having trouble having your extension delegate add this line to your ...App.swift file.
    @WKExtensionDelegateAdaptor(ExtensionDelegate.self) var appDelegate
Complication not updating after 5 days
 
 
Q