Skip to content

Commit 89d3491

Browse files
authored
fix: Unfinished migration on fail in one legacy library [FC-0107] (#37521)
- Fix the issue described in openedx/frontend-app-authoring#2169 (comment) - Adds `is_failed` field to migrations. - Adds the logic of partial migration: If the import of a library fails, then mark it as failed and continue with the next library.
1 parent 774f3b3 commit 89d3491

6 files changed

Lines changed: 334 additions & 193 deletions

File tree

cms/djangoapps/modulestore_migrator/api.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,9 @@ def get_migration_info(source_keys: list[CourseKey | LibraryLocator]) -> dict:
125125
return {
126126
info.key: info
127127
for info in ModulestoreSource.objects.filter(
128-
migrations__task_status__state=UserTaskStatus.SUCCEEDED, key__in=source_keys
128+
migrations__task_status__state=UserTaskStatus.SUCCEEDED,
129+
migrations__is_failed=False,
130+
key__in=source_keys,
129131
)
130132
.values_list(
131133
'migrations__target__key',
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 4.2.24 on 2025-10-21 23:37
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('modulestore_migrator', '0002_alter_modulestoremigration_task_status'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='modulestoremigration',
15+
name='is_failed',
16+
field=models.BooleanField(default=False, help_text='is the migration failed?'),
17+
),
18+
]

cms/djangoapps/modulestore_migrator/models.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class ModulestoreSource(models.Model):
4141
)
4242

4343
def __str__(self):
44-
return f"{self.__class__.__name__}('{self.key}')"
44+
return f"{self.key}"
4545

4646
__repr__ = __str__
4747

@@ -131,6 +131,17 @@ class ModulestoreMigration(models.Model):
131131
"We temporarily save the staged content to allow for troubleshooting of failed migrations."
132132
)
133133
)
134+
# Mostly used in bulk migrations. The `UserTaskStatus` represents the status of the entire bulk migration;
135+
# a `FAILED` status means that the entire bulk-migration has failed.
136+
# Each `ModulestoreMigration` saves the data of the migration of each legacy library.
137+
# The `is_failed` value is to keep track a failed legacy library in the bulk migration,
138+
# but allow continuing with the migration of the rest of the legacy libraries.
139+
is_failed = models.BooleanField(
140+
default=False,
141+
help_text=_(
142+
"is the migration failed?"
143+
),
144+
)
134145

135146
def __str__(self):
136147
return (

cms/djangoapps/modulestore_migrator/rest_api/v1/serializers.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ class ModulestoreMigrationSerializer(serializers.Serializer):
5353
required=False,
5454
default=False,
5555
)
56+
is_failed = serializers.BooleanField(
57+
help_text="It is true if this migration is failed",
58+
required=False,
59+
default=False,
60+
)
5661

5762
def get_fields(self):
5863
fields = super().get_fields()

0 commit comments

Comments
 (0)