Acknowledged
CIQQA-3260

UI Freeze Due to Long Pre-processing Delay Before onReceive

I'm working on a Connect IQ app that processes JSON responses, which can grow quite large—sometimes approaching the size limit that triggers a -402 response code.

With these large responses, I’ve observed on my physical Epix 2 Pro that the pre-processing phase—the time between the response arriving and the onReceive callback being invoked—can occasionally take an unusually long time. While this phase typically lasts between 150ms and 300ms, I’ve seen it spike up to 10,000ms.

The main problem with that is it blocks all other events from being processed during that time—including user input—effectively freezing the UI.

What I’d expect from the API:

If the API’s internal pre-processing of a response occasionally takes longer, I would expect it to be handled in a non-blocking way—allowing the app to remain responsive and continue handling user input.

How I measured this:

I’m not sure if this is the precise terminology, but let’s assume the CIQ engine maintains an event queue that handles user input, timer events, and web request responses.

Here's the approach: after calling makeWebRequest, control is returned to the app, which continues processing other events. When the response arrives, it triggers a new event for processing the response and invoking onReceive.

To measure the timing, I record the moment makeWebRequest is called using System.getTimer(). Then I schedule recurring 50ms timer events, each logging the time elapsed since the request. When onReceive is eventually called, I measure the time again. The gap between the last timer event and the onReceive timestamp gives an estimate of how long the pre-processing phase took after the response arrived.

This method offers a resolution of 50ms, so it’s not highly precise—but it's sufficient for spotting significant delays.

You can find the relevant code here:
https://github.com/TheNinth7/ohg/blob/onReceiveDelayTest/source/web-requests/sitemap/SitemapRequest.mc
Focus on the makeWebRequest, onReceive, and TimeMeasurerTask functions. For response handling, I use a task queue whose primary purpose is to split up processing into smaller chunks—so the main thread isn't blocked for too long at once.

Test data and observations:

The test data shown below comes from two separate runs, identifiable by their timestamps. In the first run, the delay occurred as early as the third request. In the second, it took longer to reproduce, suggesting that the issue occurs sporadically.

31.5.2025 7:52:45: SitemapRequest.makeRequest: #1
31.5.2025 7:52:49: SitemapRequest.onReceive: #1
31.5.2025 7:52:49: SitemapRequest.onReceive: total=4645ms pre-processing=188ms
31.5.2025 7:52:51: SitemapRequest.makeRequest: #2
31.5.2025 7:52:51: SitemapRequest.onReceive: end
31.5.2025 7:52:52: SitemapRequest.onReceive: #2
31.5.2025 7:52:52: SitemapRequest.onReceive: total=1070ms pre-processing=148ms
31.5.2025 7:52:52: SitemapRequest.onReceive: end
31.5.2025 7:53:11: SitemapRequest.makeRequest: #3
31.5.2025 7:53:17: SitemapRequest.onReceive: #3
31.5.2025 7:53:17: SitemapRequest.onReceive: total=6643ms pre-processing=5262ms
31.5.2025 7:53:17: SitemapRequest.onReceive: end
31.5.2025 7:53:18: HomepageMenuDelegate.onBack
31.5.2025 7:56:49: SitemapRequest.makeRequest: #1
31.5.2025 7:56:50: SitemapRequest.onReceive: #1
31.5.2025 7:56:50: SitemapRequest.onReceive: total=1025ms pre-processing=171ms
31.5.2025 7:56:52: SitemapRequest.makeRequest: #2
31.5.2025 7:56:52: SitemapRequest.onReceive: end
31.5.2025 7:56:53: SitemapRequest.onReceive: #2
31.5.2025 7:56:53: SitemapRequest.onReceive: total=1080ms pre-processing=151ms
31.5.2025 7:56:53: SitemapRequest.onReceive: end
31.5.2025 7:57:2: SitemapRequest.makeRequest: #3
31.5.2025 7:57:9: SitemapRequest.onReceive: #3
31.5.2025 7:57:9: SitemapRequest.onReceive: total=7964ms pre-processing=7093ms
31.5.2025 7:57:10: SitemapRequest.onReceive: end
31.5.2025 7:57:17: SitemapRequest.makeRequest: #4
31.5.2025 7:57:19: SitemapRequest.onReceive: #4
31.5.2025 7:57:19: SitemapRequest.onReceive: total=1711ms pre-processing=302ms
31.5.2025 7:57:19: SitemapRequest.onReceive: end
31.5.2025 7:57:37: SitemapRequest.makeRequest: #5
31.5.2025 7:57:39: SitemapRequest.onReceive: #5
31.5.2025 7:57:39: SitemapRequest.onReceive: total=1960ms pre-processing=157ms
31.5.2025 7:57:39: SitemapRequest.onReceive: end
31.5.2025 7:57:58: SitemapRequest.makeRequest: #6
31.5.2025 7:58:0: SitemapRequest.onReceive: #6
31.5.2025 7:58:0: SitemapRequest.onReceive: total=1990ms pre-processing=212ms
31.5.2025 7:58:0: SitemapRequest.onReceive: end
31.5.2025 7:58:20: SitemapRequest.makeRequest: #7
31.5.2025 7:58:21: SitemapRequest.onReceive: #7
31.5.2025 7:58:21: SitemapRequest.onReceive: total=1696ms pre-processing=148ms
31.5.2025 7:58:21: SitemapRequest.onReceive: end
31.5.2025 7:58:45: SitemapRequest.makeRequest: #8
31.5.2025 7:58:48: SitemapRequest.onReceive: #8
31.5.2025 7:58:48: SitemapRequest.onReceive: total=3280ms pre-processing=1238ms
31.5.2025 7:58:48: SitemapRequest.onReceive: end
31.5.2025 7:58:49: HomepageMenuDelegate.onBack

You might also notice that the initial request sometimes takes a very long time—I’ve observed delays of up to 28 seconds. Again, this doesn’t happen consistently. Importantly, this time isn’t spent in the pre-processing phase, and it doesn’t block the user interface, so I believe it’s a separate issue. My guess is that it might be related to initializing the communication channel to the phone that's required to make the request—but that’s purely speculative at this point.

  • Sounds to me that the API does handle it - just not as fast as you'd like.

    I disagree—I wouldn't consider a multi-second block as "handling it." As FlowState pointed out, this only happens intermittently, so it's clearly not just a matter of processing time. There's something else going on here, though I can't say exactly what.

    The bottom line is that I believe the API could and should handle this better. Yes, workarounds exist, but they come with a cost. And really, why should every developer working with large JSON data have to reinvent the wheel when this could be addressed more effectively at the API level?

    There are better ways to manage long-running processing. Unfortunately, the Garmin API lacks support in this area. In both of my apps, I ended up writing a custom task queue to break down larger operations into smaller asynchronous tasks—leaving room in between to handle user input smoothly.

  • You are forgetting other factors such as what else the Garmin is doing at the time.

  • CIQ is single threaded so while you are doing the first part (handling the data), you can't do the second part (input).

    It actually sound to me that maybe the code handling the first part should trigger the watchdog.  This won't fix your issue.

    When the-ninth says "pre-processing (the received data)", he's referring to Garmin code which is apparently doing so, not his own code. Not sure if you got that, based on this: "while you are doing the first part (handling the data)" and this "maybe the code handling the first part should trigger the watchdog".

    Unless you were suggesting that Garmin's own code should trigger its own watchdog? By that logic, Garmin should be rewriting its own code to avoid this situation.

    Sounds to me that the API does handle it - just not as fast as you'd like.  If the response blocks the UI for a few seconds there are things in your design to consider

    You may be missing the point that the problem with the long delay happens intermittently:

    "With these large responses, I’ve observed on my physical Epix 2 Pro that the pre-processing phase—the time between the response arriving and the onReceive callback being invoked—can occasionally take an unusually long time. While this phase typically lasts between 150ms and 300ms, I’ve seen it spike up to 10,000ms."

    Your point might be more valid if the long delay happened consistently, with every request.

  • Sounds to me that the API does handle it - just not as fast as you'd like.  If the response blocks the UI for a few seconds there are things in your design to consider - such as the amount of data (as I mentioned), or even the speed you are making the requests - If you do them too often it could be more noticeable - Try spacing them out more.

    Remember you are running on a fairly slow device (vs a pc/mac).  With CIQ only being single threaded it can only do one thing at a time.

  • The way to do that is make the first part more efficient.  Maybe add a proxy to reduce how much you process or to get the data split between multiple requests

    This issue isn’t about finding workarounds. If the API accepts large requests, it should be able to handle them reliably—full stop.