diff --git a/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py b/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py index 12265c10bbfe148ea052ea2204234611981c7ee8..319debfdc7507ab41fd0027baf058e456fa09025 100644 --- a/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py +++ b/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py @@ -94,7 +94,8 @@ class Scheduler: self._scheduling_thread_running = False self._do_schedule_event = Event() super().__init__() - SchedulerSubsystemActivator.deactivate() # make sure initial status is idle + # make sure initial status is idle + models.Subsystem.Activator('scheduler').deactivate() def start_scheduling(self): '''Prepares the scheduling_units, performs one full schedule computation, and start the scheduling loop and wait for a trigger.''' @@ -206,7 +207,7 @@ class Scheduler: def schedule_fixed_time_scheduling_units(self): ''' Schedule all schedulable fixed_time scheduling units.''' - with SchedulerSubsystemActivator(): + with models.Subsystem.Activator('scheduler'): # exclude units for inactive projects mark_scheduling_units_for_inactive_projects_unschedulable() @@ -248,7 +249,7 @@ class Scheduler: def do_dynamic_schedule(self) -> models.SchedulingUnitBlueprint: '''do a full update of the schedule: schedule next scheduling unit and assign start stop times to remaining schedulable scheduling units''' - with SchedulerSubsystemActivator(): + with models.Subsystem.Activator('scheduler'): logger.info("Updating (dynamic) schedule....") scheduled_unit = self.schedule_next_scheduling_unit() @@ -816,34 +817,3 @@ def cancel_running_observation_if_needed_and_possible(candidate: ScoredSchedulin else: logger.info('NOT cancelling subtask pk=%s trigger_priority=%s for triggered scheduling_unit pk=%s trigger_priority=%s because its priority is too low' % (obs.pk, obs.project.trigger_priority, candidate.scheduling_unit.pk, candidate.scheduling_unit.project.trigger_priority)) - - - -class SchedulerSubsystemActivator: - '''Helper class to activate/deactivate the 'scheduler' subsystem entry in the database. - By using the 'with'-context manager, it is guaranteed to deactivate the setting upon scope exit (thus also by exceptions)''' - @staticmethod - def activate(): - '''activate the 'scheduler' subsystem status''' - try: - scheduler_subsytem = models.Subsystem.objects.get(name='scheduler') - scheduler_subsytem.status = models.SubsystemStatus.objects.get(value=models.SubsystemStatus.Choices.ACTIVE.value) - scheduler_subsytem.save() - except Exception as e: - logger.warning("Could not update scheduler subsystem status: %s", e) - - @staticmethod - def deactivate(): - '''deactivate the 'scheduler' subsystem status (idle)''' - try: - scheduler_subsytem = models.Subsystem.objects.get(name='scheduler') - scheduler_subsytem.status = models.SubsystemStatus.objects.get(value=models.SubsystemStatus.Choices.IDLE.value) - scheduler_subsytem.save() - except Exception as e: - logger.warning("Could not update scheduler subsystem status: %s", e) - - def __enter__(self): - self.activate() - - def __exit__(self, exc_type, exc_val, exc_tb): - self.deactivate() diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py b/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py index 873076085be2a7b002af7bafffa937b0440e7cb3..373679cb1b67a47af5c7c1e1ef908a776656e839 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py @@ -283,6 +283,37 @@ class Subsystem(NamedCommonPK): # superclass's name is primary key status = ForeignKey('SubsystemStatus', null=False, on_delete=PROTECT) + class Activator: + '''Helper class to activate/deactivate a subsystem entry in the database. + By using the 'with'-context manager, it is guaranteed to deactivate the setting upon scope exit (thus also by exceptions)''' + def __init__(self, subsystem_name: str): + self.subsystem_name = subsystem_name + + def __update_state(self, status: str): + '''update the subsystem's status''' + try: + scheduler_subsytem = Subsystem.objects.get(name=self.subsystem_name) + scheduler_subsytem.status = SubsystemStatus.objects.get(value=status) + scheduler_subsytem.save() + except Exception as e: + logger.warning("Could not update %s subsystem status: %s", self.subsystem_name, e) + + def activate(self): + '''activate the subsystem status''' + self.__update_state(SubsystemStatus.Choices.ACTIVE.value) + + def deactivate(self): + '''deactivate the subsystem status''' + self.__update_state(SubsystemStatus.Choices.IDLE.value) + + def __enter__(self): + '''activate the subsystem status upon entering the with-context''' + self.activate() + + def __exit__(self, exc_type, exc_val, exc_tb): + '''deactivate the subsystem status upon exiting the with-context''' + self.deactivate() + class TaskConnectorType(Model): ''' Describes the data type & format combinations a Task can accept or produce. The "role" is used to distinguish