fix: course import when lib block is synced#38756
Conversation
|
Thanks for the pull request, @asadali145! This repository is currently maintained by Once you've gone through the following steps feel free to tag them in a comment and let them know that your changes are ready for engineering review. 🔘 Get product approvalIf you haven't already, check this list to see if your contribution needs to go through the product review process.
🔘 Provide contextTo help your reviewers and other members of the community understand the purpose and larger context of your changes, feel free to add as much of the following information to the PR description as you can:
🔘 Get a green buildIf one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green. DetailsWhere can I find more information?If you'd like to get more details on all aspects of the review process for open source pull requests (OSPRs), check out the following resources: When can I expect my changes to be merged?Our goal is to get community contributions seen and reviewed as efficiently as possible. However, the amount of time that it takes to review and merge a PR can vary significantly based on factors such as:
💡 As a result it may take up to several weeks or months to complete a review and merge your PR. |
9165836 to
3235482
Compare
Description
Fixes a crash when importing a course containing a
library_contentblock into an environment where that course does not yet exist, but the referenced v1 library does.Problem
When exporting a course from one environment (e.g. production) and importing it into another (e.g. RC/staging) for the first time, the import fails with:
This only occurs when all three conditions are met simultaneously:
library_contentblock had its children synced from the library before export (so the exported XML contains child problem block IDs)library_contentblock has never been published there)Root Cause
The
_update_and_import_blockfunction inxml_importer.pyhas special-case handling forlibrary_contentblocks. During a course import, children are imported under thepublished_onlybranch setting.split_draft.import_xblockunder this setting imports the block to the draft branch and then immediately publishes it withblacklist=EXCLUDE_ALL(no children). It returns the published block.Two bugs compounded:
Bug 1 — sync called on wrong branch:
sync_from_library()was called on the returned published block. Thetrigger_library_syncCelery task callsstore.get_item(dest_block.scope_ids.usage_id)— since the usage ID already carriesbranch=published,_map_revision_to_branchignores the surroundingdraft_preferredbranch setting and fetches the published block.copy_from_templatethen creates child blocks only in the published structure. Whenstore.publish()subsequently copies from draft → published, the draft structure has a dangling child reference (from the XML import) but no actual block entry for it, causing theKeyError.Bug 2 — stale library version GUID:
Even after fixing Bug 1 (calling
sync_from_libraryon the draft block), the sync still silently failed.sync_from_library()withoutupgrade_to_latest=Truepassessource_library_version— a MongoDB ObjectId from the source environment's database — totrigger_library_sync. That version GUID does not exist in the destination's MongoDB, soget_library(...for_version(source_version_guid))raisesItemNotFoundError→ObjectDoesNotExist, which is swallowed by the innerexcept ObjectDoesNotExist: pass. Theelseblock then proceeds to callstore.publish()on a draft structure that still has only dangling child references — same crash.Fix
Two changes to
_update_and_import_blockinxmodule/modulestore/xml_importer.py:sync_from_libraryon it, socopy_from_templatepopulates child blocks in the draft structure (not the published structure).upgrade_to_latest=Trueso the library is resolved against the destination environment's current library head, rather than attempting to look up a version GUID from the source environment that will never exist on the destination.After these fixes,
copy_from_templatecorrectly creates child problem blocks in the draft structure, and the subsequentstore.publish()can recursively copy them from draft → published without a KeyError.Notes
Testing instructions
To reproduce the bug (before the fix), we need to have 2 open edx instances: