diff --git a/SAS/TMSS/backend/services/scheduling/lib/constraints.py b/SAS/TMSS/backend/services/scheduling/lib/constraints.py index c62762388f408e56302ff0b8878573d5c9bc498a..007d82ca2da93d3447c397ac53957bff0a0727b3 100644 --- a/SAS/TMSS/backend/services/scheduling/lib/constraints.py +++ b/SAS/TMSS/backend/services/scheduling/lib/constraints.py @@ -2039,7 +2039,7 @@ def determine_unschedulable_reason_and_mark_unschedulable_if_needed(scheduling_u upper_bound=proposed_start_time+scheduling_unit.specified_observation_duration): missing_stations = get_missing_stations_for_scheduling_unit(scheduling_unit, proposed_start_time=proposed_start_time) if missing_stations: - msg = "Stations %s are reserved" % (','.join([str(s) for s in missing_stations]), ) + msg = "Stations %s are reserved at start_time='%s'" % (','.join([str(s) for s in missing_stations]), proposed_start_time) return mark_independent_subtasks_in_scheduling_unit_blueprint_as_unschedulable(scheduling_unit, msg) blocking_units = get_blocking_scheduled_units(scheduling_unit) diff --git a/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py b/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py index 388a8fca275304736e6e540ba4d5cab59c3015d0..832bdef485096c66ca121f13c9c4262164906310 100644 --- a/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py +++ b/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py @@ -267,7 +267,18 @@ class Scheduler: self.log_schedule(log_level=logging.DEBUG) except Exception as e: logger.exception("Could not schedule fixed_time-scheduled scheduling unit id=%d: %s", schedulable_unit.id, e) - mark_independent_subtasks_in_scheduling_unit_blueprint_as_unschedulable(schedulable_unit, reason=str(e)) + unschedulable_unit = determine_unschedulable_reason_and_mark_unschedulable_if_needed(schedulable_unit, + at_timestamp, + at_timestamp + schedulable_unit.specified_observation_duration, + proposed_start_time=at_timestamp, + gridder=self.search_gridder, + raise_if_interruped=self._raise_if_triggered) + + if unschedulable_unit.status.value != models.SchedulingUnitStatus.Choices.UNSCHEDULABLE.value: + # final bail out... we could not determine_unschedulable_reason_and_mark_unschedulable_if_needed, + # so just mark it unschedulable with the exception as reason + mark_independent_subtasks_in_scheduling_unit_blueprint_as_unschedulable(schedulable_unit, reason=str(e)) + else: logger.info("there are no schedulable scheduling units with fixed_time at constraint for active projects to schedule") diff --git a/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py b/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py index e83c70587343452f207eea7edd7add4a4fffaf33..acf97988656f0d61a16eebce527c13c126186a62 100755 --- a/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py +++ b/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py @@ -3761,26 +3761,31 @@ class TestReservedStationsTimeWindows(BaseDynamicSchedulingTestCase): # set the constraints for scheduling_unit_blueprint_cs002_cs003 self.scheduling_unit_blueprint_cs002_cs003.scheduling_constraints_doc['scheduler'] = 'fixed_time' self.scheduling_unit_blueprint_cs002_cs003.scheduling_constraints_doc['time'] = { "at": reservation_two.start_time.isoformat() } - self.scheduling_unit_blueprint_cs002_cs003.scheduling_constraints_doc['sky']['transit_offset'] = { "from": -21600, "to": 21600 } # loosen constraint, so it does not interfer + # have very loose sky constraints, so this test is not time-dependent, and can run at any reservation_two.start_time + self.scheduling_unit_blueprint_cs002_cs003.scheduling_constraints_doc['sky'] = {'transit_offset': {'from': -43200, + 'to': 43200 }, + 'min_distance': {'jupiter': 0, + 'sun': 0, + 'moon': 0}, + 'min_elevation': { 'target': 0, + 'calibrator': 0}} self.scheduling_unit_blueprint_cs002_cs003.save() # mark the other units as fixed time, so they won't interfere self.scheduling_unit_blueprint.scheduling_constraints_doc = {'scheduler': 'fixed_time', 'time': {'at': (reservation_two.stop_time + timedelta(days=1)).isoformat()}} self.scheduling_unit_blueprint.save() - self.scheduling_unit_blueprint_cs002.scheduling_constraints_doc = {'scheduler': 'fixed_time', 'time': {'at': (reservation_two.stop_time + timedelta(days=1)).isoformat()}} + self.scheduling_unit_blueprint_cs002.scheduling_constraints_doc = {'scheduler': 'fixed_time', 'time': {'at': (reservation_two.stop_time + timedelta(days=2)).isoformat()}} self.scheduling_unit_blueprint_cs002.save() - # try to schedule, should fail. + # try to schedule, should fail for scheduling_unit_blueprint_cs002_cs003. wipe_evaluate_constraints_caches() scheduled_scheduling_units = self.scheduler.schedule_fixed_time_scheduling_units() # Assert the scheduling_unit has not been scheduled and that it has the correct expected unschedulable_reason self.scheduling_unit_blueprint_cs002_cs003.refresh_from_db() self.assertEqual('unschedulable', self.scheduling_unit_blueprint_cs002_cs003.status.value) - try: - self.assertEqual("Stations CS002,CS003 are reserved", self.scheduling_unit_blueprint_cs002_cs003.unschedulable_reason) - except AssertionError: - self.assertIn('Too many stations unavailable', self.scheduling_unit_blueprint_cs002_cs003.unschedulable_reason) + self.assertEqual("Stations CS002,CS003 are reserved at start_time='%s'"%(reservation_two.start_time,), + self.scheduling_unit_blueprint_cs002_cs003.unschedulable_reason) class TestTriggers(BaseDynamicSchedulingTestCase):