docs: add adr for hybrid approach (#31979)

This commit is contained in:
Jesper Hodge
2023-03-29 13:02:20 -04:00
committed by GitHub
parent 14e122f37c
commit 44334105cd

View File

@@ -0,0 +1,81 @@
0003: Hybrid approach for public course authoring APIs
======================================================
Context
-------
We are planning to offer public APIs via oauth that allow course authors to create
and update course content via an external application. The plan for this is outlined in this
`Spec Demo`_.
.. _`Spec Demo`: https://openedx.atlassian.net/wiki/spaces/COMM/pages/3696066564/Spec+Memo+API-Based+Management+of+edX+Course+Blocks+Outlines+and+Settings+MVP.
Rather than restricting a course to only ever be editable either via API or manually,
we will offer a hybrid solution where both are possible.
A hybrid solution faces two challenges:
- "out-of-date write conflicts": how do we handle a situation where an API user attempts to update
a course using a stale course snapshot as a starting point?
This creates a danger of overwriting another person's changes.
- "dirty writes": how do we handle a situation where there are multiple concurrent, asynchronous import or update
operations that may be in conflict with each other?
Some considerations that come into play when picking an approach are:
1. Having the system reliably play traffic cop isn't simple, principally because of our reliance on slow-running async tasks.
2. Even if we ignore the problem of playing traffic cop, embracing hybrid editing means clients need some way to know
whether other users have made changes.
We analyzed a range of the most viable options to handle these challenges.
We ruled out any we found to be much too risky or much too hard to implement due to a high amount of complexity.
That left us with three alternatives, of which we rejected the following two:
- adding a toggle that lets users switch the course between enforcing only manual editing
and only API editing. This toggle needs to allow for running import operations to finish before switching, thus making it complex.
- using a form of optimistic concurrency control where we expect different users and explicitly version each change, then forbid
any API operation unless the API operator provides a version identifier that is not out of date.
We rejected these challenges on the basis that they were complex to implement and make us play "Traffic cop".
However, future iterations on the API may require us to be more strict and employ further safeguards, and it remains a possibility to circle
back and add one of these options on top of what we do now initially.
Another complication is that our planned solution is limited in terms of rollback capabilities: xblocks are internally versioned
and we can use this internal versioning to offer rollback tools, and this extends to rolling back changes to their tree structure
(for example adding subtrees, reordering child xblocks, etc). However, other files that are imported, like static assets and some course-level
configuration, do not have this versioning capabilities. According to our planned architecture around these APIs, we will not support versioning
and rollback on our side. Instead, we expect users to handle this problem themselves by having backups and version control for these files independently.
We also do not offer any draft capabilities for the API; changes will be immediately published.
Decision
--------
- We consider the user responsible for avoiding, resolving, or fixing conflicts.
- Courses that are operated in this hybrid fashion - that is, they are being edited not just via studio, but also via API -
are intended to be edited by one user at a time. In the API documentation, we will ask users to follow this principle.
- While we don't plan to enforce this prohibition of concurrent users today, leaving it as a self-policing responsibility users bear,
we leave open the option of doing so in the future..
- We provide logs about past changes to the user to alert them of other users' changes.
- We provide sufficient rollback tools to fix any problems with xblocks / xblock structure the users may have caused.
Provided that modulestore versioning makes older versions of an XBlock available, we will provide a programmatic way to replace the current version
of an XBlock with an older version, referenced by version ID.
Our current goal is to offer this packaged as a "undo task" operation.
- We do not provide any versioning, rolling back, or logging for anything that is not an xblock (static assets,
course-level policies and settings, etc). We recommend that the users employ version control for this on their side.
Consequences
------------
The decision not to enforce a limit of one client at a time means that users may run into conflicts or problems if they
do not follow our instruction to work one at a time and coordinate.
Because no rollback capabilities are offered by the API for course assets, the burden of maintaining assets under external
source control falls on the user; a user's failure to do so may lead to irrevocable content loss on course corruption.
With this decision, we make clear where the responsibility lies for dealing with problems. We do not have to
build a complex mechanism to avoid or resolve conflicts ("playing traffic cop");
and consequently, we do not need to act on any errors that happen when this mechanism isn't perfect.
However, there may very well arise the needs to add safeguards in the future. The most straightforward and simple action would be to
actually enforce this one-concurrent-user policy and not allowing more than one user to edit concurrently.