From d873876fed8fb27e32729791e492e1fc2cece600 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 5 Aug 2026 15:37:07 -0400 Subject: [PATCH] Batch migration updates --- .../migrations/0025_add_job_execution_time.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/netbox/core/migrations/0025_add_job_execution_time.py b/netbox/core/migrations/0025_add_job_execution_time.py index baf4be931..049bc7ab2 100644 --- a/netbox/core/migrations/0025_add_job_execution_time.py +++ b/netbox/core/migrations/0025_add_job_execution_time.py @@ -1,15 +1,28 @@ from django.db import migrations, models from django.db.models import DurationField, ExpressionWrapper, F +BATCH_SIZE = 5000 + def populate_execution_time(apps, schema_editor): """ Populate execution_time for existing jobs which have both a start and completion time recorded. + Updates are performed in batches, as installations which retain job history indefinitely can + accumulate a very large number of rows. """ Job = apps.get_model("core", "Job") - Job.objects.filter(started__isnull=False, completed__isnull=False).update( - execution_time=ExpressionWrapper(F("completed") - F("started"), output_field=DurationField()) - ) + queryset = Job.objects.filter(started__isnull=False, completed__isnull=False) + execution_time = ExpressionWrapper(F("completed") - F("started"), output_field=DurationField()) + + last_pk = 0 + while True: + pks = list( + queryset.filter(pk__gt=last_pk).order_by("pk").values_list("pk", flat=True)[:BATCH_SIZE] + ) + if not pks: + break + Job.objects.filter(pk__in=pks).update(execution_time=execution_time) + last_pk = pks[-1] class Migration(migrations.Migration):