diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/models/scheduling.py b/SAS/TMSS/backend/src/tmss/tmssapp/models/scheduling.py index 1d743ff33d751b4b14738e57d0b915d4dafbcfd8..9f1dc953a20a865a13c4fefb49f2c80bcb072b32 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/models/scheduling.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/models/scheduling.py @@ -172,6 +172,11 @@ class Subtask(BasicCommon, ProjectPropertyMixin, TemplateSchemaMixin): else: self.__original_obsolete_since = None + @property + def is_obsolete(self) -> bool: + '''convenience property turning the obsolete_since timestamp into a boolean''' + return self.obsolete_since is not None + @property def duration(self) -> timedelta: '''the duration of this subtask (stop-start), or 0 if start/stop are None''' diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/subtasks.py b/SAS/TMSS/backend/src/tmss/tmssapp/subtasks.py index 7b1d1931bb25ca1dc9921429c3171b077d2afef9..0c699a9536f14cb8f9d6f2463fe8339930b316e2 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/subtasks.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/subtasks.py @@ -1101,6 +1101,11 @@ def check_prerequities_for_scheduling(subtask: Subtask) -> bool: for predecessor in subtask.predecessors.all(): if predecessor.state.value != SubtaskState.Choices.FINISHED.value: + if predecessor.is_obsolete: + logger.info("Ignoring subtask id=%s's predecessor id=%s with state='%s' while scheduling because it is marked obsolete", + subtask.pk, predecessor.pk, predecessor.state.value) + continue + raise SubtaskSchedulingException("Cannot schedule subtask id=%d because its predecessor id=%s in not FINISHED but state=%s" % (subtask.pk, predecessor.pk, predecessor.state.value)) diff --git a/SAS/TMSS/backend/test/t_scheduling.py b/SAS/TMSS/backend/test/t_scheduling.py index 1968b2e91134808c2d2cb0635413cff6af1ff2be..92da7f2e8d7ef6830cc83e6905c16381af9d2069 100755 --- a/SAS/TMSS/backend/test/t_scheduling.py +++ b/SAS/TMSS/backend/test/t_scheduling.py @@ -466,11 +466,28 @@ class SchedulingTest(unittest.TestCase): "preprocessing pipeline", {}) + # cancel the observation obs_subtask = client.cancel_subtask(obs_subtask['id']) + + # check, should be cancelled, but not obsolete self.assertEqual('cancelled', obs_subtask['state_value']) + self.assertIsNone(obs_subtask['obsolete_since']) - pipe_subtask = client.schedule_subtask(pipe_subtask['id']) + # scheduling pipeline should fail + with self.assertRaises(Exception) as context: + pipe_subtask = client.schedule_subtask(pipe_subtask['id']) + self.assertTrue('Cannot schedule subtask' in str(context.exception)) + self.assertTrue('not FINISHED but state=cancelled' in str(context.exception)) + + # now mark the cancelled observation as obsolete + obs_subtask = client.mark_subtask_as_obsolete(obs_subtask['id']) + # check, should (still) be cancelled, and now obsolete + self.assertEqual('cancelled', obs_subtask['state_value']) + self.assertIsNotNone(obs_subtask['obsolete_since']) + + # scheduling pipeline should now be a success + pipe_subtask = client.schedule_subtask(pipe_subtask['id']) self.assertEqual('scheduled', pipe_subtask['state_value']) self.assertEqual('scheduled', tmss_test_env.ra_test_environment.radb.getTask(tmss_id=pipe_subtask['id'])['status'])