-
Notifications
You must be signed in to change notification settings - Fork 733
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
Add side loading for single user sync of data that does not fall within single user scope #8079
Comments
We realized an issue with the current specifications, for some more complex scenarios involving SoUDs syncing with more than one full-facility servers that may themselves not be fully synced with one another (and used by different teachers). This is a tangible reality for S2S, where there are 3 teachers per school each with their own laptop for different subjects, with the same facilities and user accounts across them (but only syncing with one another intermittently). Learner tablets will connect with a particular teacher laptop depending on which teacher they're currently visiting. The scenario of concern is as follows:
The proposed solution is to go back to an earlier-brainstormed approach that involves creating a syncable record of each assignment that is specific to the individual student, and is scoped into their single-user read-only partition. The proposed approach is:
The approach above gains its efficiency/correctness from being able to lean on Morango's "history tracking", to know when a record on one side vs the other has changed relative to a common ancestor. Specifically, it would address the scenario described above in the following way (where "IA" is shorthand for "IndividualAssignment"):
On the other hand, if Laptop A and B had already synced, and then a teacher un-assigned Lesson X on Laptop B, before syncing with the tablet, the IA X that had already been synced to Laptop B would now be deleted when the tablet syncs with Laptop B, and the deletion would be propagated to the tablet as desired. Working through a slight variation in the scenario:
So the tradeoff with the new approach (as proposed here) is that assigned materials may not disappear from limited devices as quickly. This seems better than the alternative (having stuff disappear prematurely), particularly because it's a much less likely scenario for our currently known primary use case, as the multiple school servers for S2S will largely be used to assign disjoint sets of lessons (as they're managed by different teachers, of different subjects). And worst case, it just means having some lessons stick around a bit longer. However, it's still not 100% ideal. The only approach I can think of that would work around this completely would be to have IA creation happen at the time of assigning or unassigning (rather than on-demand during syncing, for that particular user), based on signal listeners or similar. My main concerns with doing that would be increased database overhead every time an operation happens that impacts Lesson/Quiz or Assignment objects, rather than being as focal or on-demand. |
A parallel question for @bjester around how best to tie something like this into the middleware/scenario operations sequencing stuff: what would be the best way to have specific operations that occur on the full and limited devices (a different operation on each) as part of an individual-user-sync process, regardless of which side initiated? For whichever side is the client in the relationship, I think I could imagine from what you showed how to inject some operations into that sequence, but I'm not sure the symmetry of these scenarios in terms of being able to specify custom stuff that happens on the server side at different parts of the sync process. |
Another alternative would be to have IA creation/deletion also happen during full-facility syncs between the full devices (the laptops, in the scenarios above). This still adds a bit of overhead, but much less frequently than if we were doing it whenever a change happened. We'd then still need to also do it as part of the individual user sync in case further changes happened on that full device prior to the individual user sync. Given the extra bloat and overhead, we'd want to ensure we only did this for users likely to be individually synced (so maybe we'd set a flag on |
@jamalex I think this can be handled through the default middleware configuration which will be configurable through settings. The default middleware is used by both client and server (by default), so the only requirement would be that it is able to detect from the context object that it should actually do something. So for instance, a custom middleware operation could be prepended to the cleanup stage. I would expect this operation to always return |
Overall this seems fine to me, and I prefer it to the API-based side channel. (If we ever revisit that, recommend considering An edge-case limitation of the Morango
This does not seem particularly problematic because typically (in S2S at least) devices A and B will be used by different coaches for different classes, so they likely won't expect or need to see assignments from each other. I do have a more general concern about the long-term added complexity of a new serialization and deserialization layer, but I understand that it may be unavoidable. One alternative variation we discussed might alleviate this:
I think this was deemed infeasible for backward-compatibility reasons, and we briefly discussed what it would take to address that but didn't come up with specific proposals. Thanks for the thorough analysis all! |
Yes, exactly -- @rtibbles and I chatted about this, and agree for the S2S use case it's not a concern. And we can easily add the "create IA's on full-facility-sync for users that have done single-user-syncs previously" in future versions if it starts to look like a practical issue.
The main thing that makes this messy is that many ways that a user can come to be assigned something:
So one thing @rtibbles and I talked about was that if we did essentially go with the "IA's should always represent current assignment state", we still need the current type of collection-level assignment structures so that we can re-compute the IA's when stuff changes (on local activity as well as stuff syncing in). And that's compatible with the direction this is heading in -- but for now we're only generating the IA's at the time a single-user sync happens. |
Fixed in #8219 |
This issue shall serve as the tech spec for #8038
The partitions for Lessons, Quizzes, and their respective Assignments do not fall within the scope of an individual user syncing certificate, and hence need to be synced across to a SoUD through a parallel (non-Morango) mechanism. However, this can still happen within the context of a Morango sync session, and use the open sync session as a means of authentication.
The proposal is to add a new public API endpoint in Kolibri,
/api/public/assignment_sync/<user_id>
, that can handleHEAD
requests (to check the server's current ETag value before sending a bunch of data),GET
requests (to retrieve the current set of assigned resources), andPOST
requests (to send the current set of assigned resources).When the SoUD is the client, initiating a sync with a full-facility server:
GET
request to/api/public/assignment_sync/<user_id>
.304 Not Modified
.When the full-facility device is the client, initiating a sync with the SoUD:
HEAD
request to the SoUD's/api/public/assignment_sync/<user_id>
to check its ETag.GET
request to the endpoint, then removes and replaces its local resources with the response.All of these requests will include a header with the Sync Session ID. The server should validate that:
401 Unauthorized
.403 Forbidden
.400 Bad Request
.The proposed structure of the serialized payload is:
There should be no need to sync the *Assignment objects themselves, as they are implicit in the lists of resources (these are all-inclusive lists of the resources currently assigned, so assignments can be deleted or created based on presence of a resource in here).
Note: when quiz/lesson resource and assignment model instances are created on a SoUD, they should be marked as "not dirty" to prevent unnecessary serialization (that could also cause issues if the device later synced the full facility). Similarly, the signal that tracks model deletion should be bypassed when they are removed.
The text was updated successfully, but these errors were encountered: