diff --git a/tr_sys/tr_ars/migrations/0015_querygraphplus.py b/tr_sys/tr_ars/migrations/0015_querygraphplus.py new file mode 100644 index 00000000..91164399 --- /dev/null +++ b/tr_sys/tr_ars/migrations/0015_querygraphplus.py @@ -0,0 +1,22 @@ +# Generated by Django 3.2.23 on 2025-02-25 18:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tr_ars', '0014_auto_20250121_2122'), + ] + + operations = [ + migrations.CreateModel( + name='QueryGraphPlus', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('timestamp', models.DateTimeField(auto_now_add=True)), + ('query_graph', models.JSONField(null=True)), + ('stats', models.JSONField(null=True)), + ], + ), + ] diff --git a/tr_sys/tr_ars/migrations/0016_auto_20250227_1636.py b/tr_sys/tr_ars/migrations/0016_auto_20250227_1636.py new file mode 100644 index 00000000..a0b93c1d --- /dev/null +++ b/tr_sys/tr_ars/migrations/0016_auto_20250227_1636.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.23 on 2025-02-27 16:36 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tr_ars', '0015_querygraphplus'), + ] + + operations = [ + migrations.AddField( + model_name='querygraphplus', + name='num_res', + field=models.IntegerField(default=None, null=True), + ), + migrations.AddField( + model_name='querygraphplus', + name='status', + field=models.CharField(choices=[('D', 'Done'), ('S', 'Stopped'), ('R', 'Running'), ('E', 'Error'), ('W', 'Waiting'), ('U', 'Unknown')], db_index=True, default='R', max_length=2), + ), + ] diff --git a/tr_sys/tr_ars/models.py b/tr_sys/tr_ars/models.py index 4785da9b..ca82eeba 100644 --- a/tr_sys/tr_ars/models.py +++ b/tr_sys/tr_ars/models.py @@ -16,6 +16,30 @@ class Meta: def to_dict(self): return json.loads(serializers.serialize('json', [self]))[0] +class QueryGraphPlus(models.Model): + STATUS = ( + ('D', 'Done'), + ('S', 'Stopped'), + ('R', 'Running'), + ('E', 'Error'), + ('W', 'Waiting'), + ('U', 'Unknown') + ) + timestamp = models.DateTimeField(auto_now_add=True) + query_graph = models.JSONField(null=True) + status = models.CharField(max_length=2, choices=STATUS, db_index=True, default='R') + num_res = models.IntegerField(null=True, default=None) + stats = models.JSONField(null=True) + + @classmethod + def create(self, *args, **kwargs): + # convert status long name to code for saving + logger.info('creating queryGraphPlus model instance') + return QueryGraphPlus(*args, **kwargs) + + def save(self, *args, **kwargs): + super().save(*args, **kwargs) + class Client(ARSModel): client_id= models.TextField('name of client',null =False) client_secret=models.TextField('hash of client secret', null = False) @@ -81,7 +105,6 @@ class Message(ARSModel): ('W', 'Waiting'), ('U', 'Unknown') ) - id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, db_index=True) name = models.SlugField('Message name', null=False) code = models.PositiveSmallIntegerField('HTTP status code', diff --git a/tr_sys/tr_ars/signals.py b/tr_sys/tr_ars/signals.py index bff4e0b0..9c8a2734 100644 --- a/tr_sys/tr_ars/signals.py +++ b/tr_sys/tr_ars/signals.py @@ -1,13 +1,15 @@ import gzip from django.shortcuts import get_object_or_404 +from django.http import HttpResponse from django.db.models.signals import post_save, pre_save from django.dispatch import receiver import sys, logging -from .models import Actor, Agent, Message, Channel +from .models import Actor, Agent, Message, Channel, QueryGraphPlus from .pubsub import send_messages from .utils import get_safe logger = logging.getLogger(__name__) from .api import query_event_unsubscribe +from django.db import IntegrityError, OperationalError @receiver(post_save, sender=Actor) def actor_post_save(sender, instance, **kwargs): @@ -44,7 +46,7 @@ def message_post_save(sender, instance, **kwargs): # check if parent status should be updated to 'Done' if message.ref is not None and message.status in ['D', 'S', 'E', 'U']: logger.info('+++ checking parent Doneness: %s for message/parent: %s %s' % (message.ref.status, str(message.id), str(message.ref.id))) - + stat_plus={} pmessage = message.ref if pmessage.status != 'D': logger.info('+++ Parent message not Done for: %s' % (str(pmessage.id))) @@ -73,6 +75,25 @@ def message_post_save(sender, instance, **kwargs): pmessage.code = 200 pmessage.save(update_fields=['status','code']) query_event_unsubscribe(None, pmessage.pk) + + try: + for child in children: + stat_plus[child.actor.inforesid]=(child.code, child.result_count, child.result_stat) + if child.actor.agent.name == 'ars-ars-agent': + result_count = child.result_count + data=pmessage.decompress_dict() + querygraph = QueryGraphPlus.create(status=pmessage.status,num_res=result_count, + query_graph=data['message']['query_graph'], + timestamp=pmessage.updated_at, stats=stat_plus) + querygraph.save() + + except OperationalError as e: + return HttpResponse('DB Operational error : %s' % str(e),status=404) + except IntegrityError as e: + return HttpResponse('DB Integrity error :%s with message %s' % (e.__cause__, str(e)), status=400) + except Exception as e: + return HttpResponse('failing due to %s with the message %s' % (e.__cause__, str(e)), status=400) + elif pmessage.status == 'E': query_event_unsubscribe(None, pmessage.pk)