From e3c9bc6b5390140bd1f860f6e2ce986ff18f04b0 Mon Sep 17 00:00:00 2001
From: Vermaas <vermaas@astron.nl>
Date: Mon, 12 Feb 2024 12:01:43 +0100
Subject: [PATCH] cleaned signals

---
 atdb/atdb/settings/base.py                    |  2 +-
 atdb/taskdatabase/admin.py                    |  6 +++-
 .../migrations/0041_alter_task_activity.py    | 19 ++++++++++++
 atdb/taskdatabase/models.py                   | 30 ++++++++++++++++---
 atdb/taskdatabase/services/activities.py      | 24 ++-------------
 atdb/taskdatabase/services/signals.py         |  5 ----
 .../templates/taskdatabase/index.html         |  2 +-
 atdb/taskdatabase/views.py                    | 16 ++++++++--
 8 files changed, 67 insertions(+), 37 deletions(-)
 create mode 100644 atdb/taskdatabase/migrations/0041_alter_task_activity.py

diff --git a/atdb/atdb/settings/base.py b/atdb/atdb/settings/base.py
index 5511fbbd..814f2d8b 100644
--- a/atdb/atdb/settings/base.py
+++ b/atdb/atdb/settings/base.py
@@ -209,7 +209,7 @@ ACTIVE_STATUSSES = ['staging','staged','processing','processed','validated','sto
 STATUSSES_WITH_DATA = ['staged','fetching','fetched','processing','processed','validated','storing','stored','scrubbing','scrubbed','archiving','archived']
 AGGREGATES = ['failed','active','total']
 
-QUERY_LIMIT_MULTI_CHANGE = 5000
+QUERY_LIMIT_MULTI_CHANGE = 10000
 MAX_MONITORING_HISTORY_HOURS = 7 * 24
 SERVICES_LATE_WARNING_SECONDS = 1800
 
diff --git a/atdb/taskdatabase/admin.py b/atdb/taskdatabase/admin.py
index b659eaf4..cc5cab80 100644
--- a/atdb/taskdatabase/admin.py
+++ b/atdb/taskdatabase/admin.py
@@ -8,7 +8,11 @@ class TaskAdmin(admin.ModelAdmin):
     ordering = ['-creationTime']
     search_fields = ['id','sas_id']
 
-admin.site.register(Activity)
+@admin.register(Activity)
+class ActivityAdmin(admin.ModelAdmin):
+    ordering = ['-sas_id']
+    search_fields = ['id','sas_id']
+
 admin.site.register(Workflow)
 admin.site.register(LogEntry)
 admin.site.register(Configuration)
diff --git a/atdb/taskdatabase/migrations/0041_alter_task_activity.py b/atdb/taskdatabase/migrations/0041_alter_task_activity.py
new file mode 100644
index 00000000..c276e0f7
--- /dev/null
+++ b/atdb/taskdatabase/migrations/0041_alter_task_activity.py
@@ -0,0 +1,19 @@
+# Generated by Django 5.0 on 2024-02-12 10:19
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('taskdatabase', '0040_activity_ingestq_status'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='task',
+            name='activity',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='tasks', to='taskdatabase.activity'),
+        ),
+    ]
diff --git a/atdb/taskdatabase/models.py b/atdb/taskdatabase/models.py
index 877ad03b..042a31db 100644
--- a/atdb/taskdatabase/models.py
+++ b/atdb/taskdatabase/models.py
@@ -76,6 +76,25 @@ def convert_summary_to_list_for_template(task):
 
     return list
 
+def associate_task_with_activity(task):
+
+    if not task.activity:
+
+        try:
+            activity = Activity.objects.get(sas_id=task.sas_id)
+        except:
+            # no activity exists yet, create it
+            logger.info(f'create new activity for sas_id {task.sas_id}')
+
+            activity = Activity(sas_id=task.sas_id,
+                                project=task.project,
+                                workflow_id = task.workflow.id,
+                                filter=task.filter)
+            activity.save()
+
+        task.activity = activity
+
+    return task.activity
 
 class Activity(models.Model):
     """
@@ -156,7 +175,7 @@ class Task(models.Model):
     joined_output_task = models.ForeignKey('self', related_name='joined_input_tasks', on_delete=models.SET_NULL, null=True, blank=True)
 
     # pipeline or observation
-    activity = models.ForeignKey(Activity, related_name='tasks', on_delete=models.DO_NOTHING, null=True, blank=True)
+    activity = models.ForeignKey(Activity, related_name='tasks', on_delete=models.SET_NULL, null=True, blank=True)
 
     def __str__(self):
         return str(self.id) + ' - (' + self.task_type + ') - ' + str(self.sas_id)
@@ -184,9 +203,12 @@ class Task(models.Model):
             tasks_for_this_sasid = Task.objects.filter(sas_id=self.sas_id)
             self.calculated_qualities = qualities.calculate_qualities(self, tasks_for_this_sasid, quality_thresholds)
 
-            # remark:
-            # a post_save signal is triggered by this save()
-            # to update the associated 'activity' with relevant aggregated information
+        # make sure that every task has an activity (backward compatibility)
+        associate_task_with_activity(self)
+
+        # remark:
+        # a post_save signal is triggered by this save()
+        # to update the associated 'activity' with relevant aggregated information
 
         super(Task, self).save(*args, **kwargs)
 
diff --git a/atdb/taskdatabase/services/activities.py b/atdb/taskdatabase/services/activities.py
index 29ea569b..1ba2771d 100644
--- a/atdb/taskdatabase/services/activities.py
+++ b/atdb/taskdatabase/services/activities.py
@@ -65,27 +65,6 @@ def calculate_finished_fraction(this_task):
 
         return result
 
-def associate_task_with_activity(task, save_task=True):
-
-    if not task.activity:
-
-        try:
-            activity = Activity.objects.get(sas_id=task.sas_id)
-        except:
-            # no activity exists yet, create it
-            logger.info(f'create new activity for sas_id {task.sas_id}')
-
-            activity = Activity(sas_id=task.sas_id,
-                                project=task.project,
-                                workflow_id = task.workflow.id,
-                                filter=task.filter)
-            activity.save()
-
-        task.activity = activity
-        if save_task:
-            task.save()
-
-    return task.activity
 
 def update_activity(task):
     """
@@ -104,7 +83,8 @@ def update_activity(task):
 
     # do not save the task,
     # because this function is called from signals where the task.save is delayed on purpose to avoid recursion
-    activity = associate_task_with_activity(task, save_task=False)
+    #activity = associate_task_with_activity(task, save_task=False)
+    activity = task.activity
 
     # depending on the status transition, perform calculations
     if task.status == State.STORED.value:
diff --git a/atdb/taskdatabase/services/signals.py b/atdb/taskdatabase/services/signals.py
index 027b7385..146c313c 100644
--- a/atdb/taskdatabase/services/signals.py
+++ b/atdb/taskdatabase/services/signals.py
@@ -69,13 +69,8 @@ def handle_post_save(sender, **kwargs):
     """
     task = kwargs.get('instance')
 
-    # temporarily disconnect and save later, to avoid recursion.
     update_activity(task)
 
-    disconnect_signals()
-    task.save()
-    connect_signals()
-
 
 def connect_signals():
     #logger.info("connect_signals")
diff --git a/atdb/taskdatabase/templates/taskdatabase/index.html b/atdb/taskdatabase/templates/taskdatabase/index.html
index 17e56897..d85e5d23 100644
--- a/atdb/taskdatabase/templates/taskdatabase/index.html
+++ b/atdb/taskdatabase/templates/taskdatabase/index.html
@@ -31,7 +31,7 @@
             {% include 'taskdatabase/pagination.html' %}
         </div>
     </div>
-    <p class="footer"> Version 9 Feb 2024
+    <p class="footer"> Version 12 Feb 2024
 </div>
 
 {% include 'taskdatabase/refresh.html' %}
diff --git a/atdb/taskdatabase/views.py b/atdb/taskdatabase/views.py
index d32fae34..eabf797e 100644
--- a/atdb/taskdatabase/views.py
+++ b/atdb/taskdatabase/views.py
@@ -23,7 +23,9 @@ from rest_framework.request import Request
 
 from django.conf import settings
 from .models import Activity, Task, Workflow, LogEntry, Configuration, Job, PostProcessingRule, Monitor, LatestMonitor
+from .models import associate_task_with_activity
 from .services.common import State
+from .services.signals import disconnect_signals, connect_signals
 from .tables import TaskTable
 from .forms import QualityAnnotationForm, DiscardAnnotationForm
 
@@ -69,6 +71,7 @@ class TaskFilter(filters.FilterSet):
             # http://localhost:8000/atdb/tasks/?predecessor__isnull=True
             'predecessor': ['isnull'],
             'predecessor__status': ['exact', 'icontains', 'in', 'startswith'],
+            'activity__id': ['exact'],
         }
 
 
@@ -1679,16 +1682,23 @@ class GetUniqueValuesForKey(generics.ListAPIView):
 
 @staff_member_required
 def AssociateActivities(request):
+    # disconnect the signals to avoid save recursion
+    disconnect_signals()
 
-    tasks = Task.objects.all().only('sas_id')
+    #tasks = Task.objects.all().only('sas_id')
+    tasks = Task.objects.filter(activity__isnull=True)
     total = tasks.count()
     i = 0
     for task in tasks:
         i+=1
-        if task.status not in ['discarded', 'suspended']:
-            activities.associate_task_with_activity(task)
+        if not task.activity:
+            if task.status not in ['discarded', 'suspended']:
+                # saving triggers a call to associate_task_with_activity(task)
+                task.save()
+
         logger.info(f'{i} of {total}')
 
+    connect_signals()
     return redirect('index')
 
 @staff_member_required
-- 
GitLab