Skip to content

Improve status functionality and update question status according to service usage events #65

@thclark

Description

@thclark

Feature request

Use Case

We want to update the status of Question entries based on the service usage events that we handle, so the status is always correct.

Current state

A number of status updates are missing

Proposed Solution

  • Update to 'in-progress' status on ask()
  • If ask() fails then update the exception status
  • On receipt of result, update to success status
  • On timeout (no heartbeats), change result to failed
  • Add and raise a signal explicitly for status change (eg to which an app could hook in order to issue update through a socket)
  • Document the use of statuses
  • Test the update of statuses

An example of a workaround in the wild

import logging
from django_gcp.tasks import OnDemandTask

from projects.models import PowerLossQuestion
from projects.models.questions import ERROR_STATUS, IN_PROGRESS_STATUS


logger = logging.getLogger(__name__)


class PowerLossQuestionTask(OnDemandTask):
    """An on-demand task to prepare and ask a question to the power-loss service

    This process is done in an async task, rather than immediately in a request,
    because some pre-preparation of the data is undertaken within `PowerLossQuestion.ask()`
    that can take several seconds of processing time.
    """

    def run(self, question_id=None):

        logger.info("Running PowerLossQuestionTask with question_id=%s", question_id)
        if question_id is None:
            raise ValueError("Task not supplied a question ID")

        # Ensure the question is fetched along with related items required for quick preparation
        question = PowerLossQuestion.objects.select_related(
            "configuration",
            "configuration__environment",
        ).get(id=question_id)
        try:
            question.calculation_status = IN_PROGRESS_STATUS
            question.save()
            question.ask()
        except Exception as e:
            question.calculation_status = ERROR_STATUS
            question.save()
            raise e
import logging
from django.db.models.signals import post_save
from django.dispatch import receiver
from django_twined.models import ServiceUsageEvent
from django_twined.signals import exception_received, monitor_message_received, result_received

from projects.models.questions import ERROR_STATUS, IN_PROGRESS_STATUS, SUCCESS_STATUS, PowerLossQuestion


logger = logging.getLogger(__name__)


@receiver(result_received, sender=ServiceUsageEvent)
def update_question_output_values(sender, service_usage_event, **kwargs):
    # TODO make a migration to flush all prior analyses into the ServiceUsageEvents queue as question_asked and question_repsonse_updated__result events
    # then stop copying data to output_values like this
    logger.info("Result received for question %s", service_usage_event.question_id)
    # Note: the related question is the base class Question, not PowerLossQuestion. So get the instance as the subclass
    question = service_usage_event.question.as_subclass()
    question.output_values = service_usage_event.data["output_values"]
    question.answered = service_usage_event.publish_time
    question.calculation_status = SUCCESS_STATUS
    question.save()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions