-
-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Better Support for Batch Uploads of Historical HealthKit Data #17
Comments
@mjoerke Thank you for the summary and overview! I agree with the approach, and thank you for writing this down into the issue. As an additional context: I would see this functionality live in two different places:
The sync between these methods is probably an async method that allows the HealthKit module to wait for the upload process to complete and a technique that is passed in there that allows a cloud provider to pull a new sample, process it, and report success back to the HealthKit module to ensure that this is always tracked even if, e.g., the app is terminated. In addition to that, We should demonstrate some caching functionality in the Spezi Template app that catches errors in a more sophisticated way than just printing an error. These are my first thoughts on this; I will do a deeper dive later this week 🚀 |
Thank you @PSchmiedmayer! Let me know if there's any place I can contribute |
@mjoerke @bryant-jimenez Here are some additional thoughts when we tackle this issue: I would suggest a I think it makes a lot of sense to use an anchored query (we already have good extensions or this) and then use it in combination with the Once you get sample in the bulk upload I would suggest to create a Task Group to parallelize the upload up to a limit (e.g. 10 concurrent tasks) but we can start with a sequential upload. |
@PSchmiedmayer This all sounds sensible to me. Thank you for the detailed reply! To make more specific where this code would live and how it would be called, are you imagining usage that looks something like this?
In this case, would you recommend creating I also have a separate question that came up while reading the SpeziHealthKit documentation – how exactly does setting |
@mjoerke Thanks for sharing the first draft of the API surface. I would suggest the following modifications:
Yes, following these examples is the way to go 👍 Regarding background delivery: We rely on the HealthKit background upload functionality. This wakes up the app and allows you to perform some operations for a few seconds. This includes network and e.g. Firebase interaction and our Template app is setup in a way that it does this upload in the background without the user even having to open the app. We are fully at the mercy of Apple when they schedule the application wake up but we made the experience that this happens around once an hour as documented in their docs: https://developer.apple.com/documentation/healthkit/hkhealthstore/1614175-enablebackgrounddelivery |
Thank you for the suggestions and clarifications! @bryant-jimenez do you have any additional questions? (and I'm sure we will have more questions once we start building things) Re background delivery: I think this makes sense to me – HealthKit background uploading is sufficient for periodic uploads as data comes in real-time, but insufficient for large batch uploads of historical data, which will require the user to keep the application in the foreground? |
This all makes sense to me so far! Questions will come up as we implement, but at a high level I agree with all of the suggestions written here. |
@mjoerke Yes, the background upload functionally only informs the app about new datapoints in HealthKit and wakes up the app to respond to them. This is not designed for background tasks, Apple has different and limited APIs for that. |
@PSchmiedmayer Hi Paul, I would like to run through my plan for an initial implementation attempt at this: Currently, my understanding is that the I created a file
Please feel free to let me know your thoughts on this implementation plan - I also had a couple of questions below on modifications that we'll need to make for this to work and also questions for my own understanding:
@mjoerke Feel free to chime in as well with any thoughts, ideas, or suggestions! |
@bryant-jimenez Thank you for putting this together! I'll take a first stab at answering these questions, but @PSchmiedmayer is definitely the expert here. Delivery Settings New Add/Remove Functions I am unsure on:
|
@bryant-jimenez Happy to provide some input; @mjoerke correctly answered the delivery setting and the add/remove function, thank you! As noted in my last comment, we will need to:
I would suggest that this function is A few further comments about
Hope these insights already help @bryant-jimenez 🚀 |
Thanks for the feedback @PSchmiedmayer ! The need for the new Standard constraint makes sense - I just had a couple of follow up questions:
Thank you! |
|
@PSchmiedmayer We're running into an issue with protocol conformance (see here) The problem is that the
even though I have a fix here that checks whether the standard conforms to the BulkUploadConstraint at runtime, but I wanted to double check with you whether this solution is preferred. An alternative would be to more generic protocols (which could be verified at compile-time), but this might require more changes to SpeziHealthKit code |
@mjoerke @bryant-jimenez Yes, I think we won't really have a good solution here except for relying on one more runtime check. At this point the Spezi framework throws an error at startup if your standard does not conform to I would suggest to
public func dataSources(
healthStore: HKHealthStore,
standard: any Standard
) -> [any HealthKitDataSource] {
guard let healthKitConstraint = standard as? any HealthKitConstraint else {
preconditionFailure(
"""
...
"""
)
}
// ...
} This is the error that we currently throw within Spezi for use cases like this: Would also give us the advantage that an app that only uses bulk upload technically does not longer have to conform to |
Thank you @PSchmiedmayer! I've made your suggested changes here. If you think we're ready to start a PR, I'd be happy to create that. |
@mjoerke Sure, a PR is always a great idea; I am happy to add some comments and additional hints in the git diff 🚀 |
Problem
Our application relies on uploading 3 months of historical HealthKit data to our Firebase. In our application delegate, we have the following code
While this code largely works, we have encountered several issues related to batch historical data uploads:
We occasionally encounter the following error,
which I believe is due to Firebase rate limiting.
This is triggered in our application because we index on a timestamp field.
The data in our Firebase is occasionally missing entries, which I suspect is due to the WriteStream error. For example, below I compare cumulative daily step count measured on an Apple Watch directly from the Apple Health app vs. computed from our Firestore entries (filtering out step count measurements from an iPhone). There are several days on which step count is slightly undercounted (bolded).
Three months of historical data is large (on the order of 1-3GB when measured across several test users) and this upload can take several hours to complete. I am not sure if it is possible to improve this upload speed in light of rate limiting. Regardless, the app stops uploading data when it enters into the background and this is not communicated in the UI. It would be highly desirable to have a progress bar indicating upload status and/or have a local notifications trigger when the application enters the background with instructions for the user. This is a design pattern employed by many other iOS applications (e.g., Spotify, Google Drive) for long-running network tasks.
Solution
I have briefly chatted with @PSchmiedmayer about possible solution strategies. We spoke about adding additional functionality for batch uploads to the SpeziHealthKit module by
@PSchmiedmayer feel free to chime in here with more implementation-specific details or if I missed something!
Additional context
No response
Code of Conduct
The text was updated successfully, but these errors were encountered: