diff --git a/SAS/TMSS/src/tmss/tmssapp/subtasks.py b/SAS/TMSS/src/tmss/tmssapp/subtasks.py index 3fc6331628d3a50b3ef4945ddf1aa89e9a0286c7..537b7e5e64b4531e22e44f952d4c3d71f5cd156d 100644 --- a/SAS/TMSS/src/tmss/tmssapp/subtasks.py +++ b/SAS/TMSS/src/tmss/tmssapp/subtasks.py @@ -178,11 +178,11 @@ def get_related_scheduling_blueprint_task(task_blueprint): try: related_scheduling = TaskSchedulingRelationBlueprint.objects.get(first=task_blueprint) related_scheduling_task_blueprint = related_scheduling.second - except TaskRelationBlueprint.DoesNotExist: + except TaskSchedulingRelationBlueprint.DoesNotExist: try: related_scheduling = TaskSchedulingRelationBlueprint.objects.get(second=task_blueprint) related_scheduling_task_blueprint = related_scheduling.first - except TaskRelationBlueprint.DoesNotExist: + except TaskSchedulingRelationBlueprint.DoesNotExist: logger.info("No related scheduling blueprint task found for id=%d", task_blueprint.pk) return related_scheduling_task_blueprint @@ -554,6 +554,63 @@ def schedule_qaplots_subtask(qaplots_subtask: Subtask): return qaplots_subtask +def get_previous_related_task_blueprint_with_time_offset(task_blueprint): + """ + Retrieve the the previous related blueprint task object (if any) + if nothing found return None, 0. + :param task_blueprint: + :return: previous_related_task_blueprint, + time_offset (in seconds) + """ + logger.info("get_previous_related_task_blueprint_with_time_offset %s (id=%s)", task_blueprint.name, task_blueprint.pk) + previous_related_task_blueprint = None + time_offset = 0 + + scheduling_relations = list(task_blueprint.first_to_connect.all()) + list(task_blueprint.second_to_connect.all()) + for scheduling_relation in scheduling_relations: + if scheduling_relation.first.id == task_blueprint.id and scheduling_relation.placement.value == "after": + previous_related_task_blueprint = TaskBlueprint.objects.get(id=scheduling_relation.second.id) + time_offset = scheduling_relation.time_offset + + if scheduling_relation.second.id == task_blueprint.id and scheduling_relation.placement.value == "before": + previous_related_task_blueprint = TaskBlueprint.objects.get(id=scheduling_relation.first.id) + time_offset = scheduling_relation.time_offset + + return previous_related_task_blueprint, time_offset + + +def calculate_start_time(observation_subtask: Subtask): + """ + Calculate the start time of an observation subtask. It should calculate the starttime in case of 'C-T-C train' + The start time of an observation depends on the start_time+duration and offset time of the previous observation + and so its scheduling relations should be known. + If there is no previous observation the 'default' start time is in two minutes from now + For demo purposes, will be changed into dynamic scheduled in the future + Note that the method is not robust now when previous start time is unknown. Also parallel observations are + not supported yet + :param observation_subtask: + :return: start_time (utc time) + """ + previous_related_task_blueprint, time_offset = get_previous_related_task_blueprint_with_time_offset(observation_subtask.task_blueprint) + if previous_related_task_blueprint is None: + # This is the first observation so take start time 2 minutes from now + now = datetime.utcnow() + next_start_time = now + timedelta(minutes=+2, seconds=-now.second, microseconds=-now.microsecond) + else: + # Get the duration of last/previous observation + duration_in_sec = previous_related_task_blueprint.specifications_doc["duration"] + logger.info("Duration of previous observation '%s' (id=%s) is %d seconds", + previous_related_task_blueprint.pk, previous_related_task_blueprint.pk, duration_in_sec) + # Get the previous observation subtask, should actually be one + lst_previous_subtasks_obs = [st for st in previous_related_task_blueprint.subtasks.all() if st.specifications_template.type.value == SubtaskType.Choices.OBSERVATION.value] + previous_subtask_obs = lst_previous_subtasks_obs[0] + logger.info("The previous observation subtask is id=%s", previous_subtask_obs.pk) + if previous_subtask_obs.start_time is None: + logger.info("Oeps the previous start time is unknown so I can not calculate it") + next_start_time = previous_subtask_obs.start_time + timedelta(seconds=duration_in_sec+time_offset) + return next_start_time + + def schedule_observation_subtask(observation_subtask: Subtask): ''' Schedule the given observation_subtask For first observations in a 'train' of subtasks this method is typically called by hand, or by the short-term-scheduler. @@ -575,13 +632,14 @@ def schedule_observation_subtask(observation_subtask: Subtask): # step 1a: check start/stop times if observation_subtask.start_time is None: - now = datetime.utcnow() - next_start_time = now + timedelta(minutes=+2, seconds=-now.second, microseconds=-now.microsecond) + next_start_time = calculate_start_time(observation_subtask) logger.info("observation id=%s has no starttime. assigned default: %s", observation_subtask.pk, formatDatetime(next_start_time)) observation_subtask.start_time = next_start_time if observation_subtask.stop_time is None: - stop_time = observation_subtask.start_time + timedelta(minutes=+1) + duration_in_sec = observation_subtask.task_blueprint.specifications_doc["duration"] + logger.info("Duration of observation id=%s is %d seconds", observation_subtask.pk, duration_in_sec) + stop_time = observation_subtask.start_time + timedelta(seconds=duration_in_sec) logger.info("observation id=%s has no stop_time. assigned default: %s", observation_subtask.pk, formatDatetime(stop_time)) observation_subtask.stop_time = stop_time