diff --git a/SAS/ResourceAssignment/ResourceAssigner/lib/schedulers.py b/SAS/ResourceAssignment/ResourceAssigner/lib/schedulers.py index 7fe977631fe1a056ee3efff625bfafeb84ba8897..f3b1c3cf5244536396b49800b8893b5e07e09fcb 100644 --- a/SAS/ResourceAssignment/ResourceAssigner/lib/schedulers.py +++ b/SAS/ResourceAssignment/ResourceAssigner/lib/schedulers.py @@ -392,10 +392,11 @@ class PriorityScheduler(BasicScheduler): logger.debug("PriorityScheduler: task kill list is %s", kill_task_list) # update if we're blocked by an earlier task than we know so far - unkillable_task_list = [t for t in conflicting_tasks if t not in kill_task_list] - logger.debug("PriorityScheduler: unkillable task kill list is %s", unkillable_task_list) - if unkillable_task_list: - earliest_potential_starttime = min([t["endtime"] for t in unkillable_task_list]) + unkillable_task_ids = [t["id"] for t in conflicting_tasks if t not in kill_task_list] + logger.debug("PriorityScheduler: unkillable task kill list is %s", unkillable_task_ids) + if unkillable_task_ids: + # note that we need to use the endtime of the claims, as they may extend beyond the task + earliest_potential_starttime = min([c["endtime"] for c in conflicting_claims if c["task_id"] in unkillable_task_ids]) self._propose_potential_starttime(earliest_potential_starttime) return kill_task_list diff --git a/SAS/ResourceAssignment/ResourceAssigner/test/t_schedulers.py b/SAS/ResourceAssignment/ResourceAssigner/test/t_schedulers.py index cd28b91d5e5eb542e790bd1c872629da1074f4bb..9780ffee5ee9954240d2f8252e9e3677e72b2bb3 100755 --- a/SAS/ResourceAssignment/ResourceAssigner/test/t_schedulers.py +++ b/SAS/ResourceAssignment/ResourceAssigner/test/t_schedulers.py @@ -65,12 +65,13 @@ class FakeRADatabase(object): for claims in self.claims.values(): for c in claims: - overlap = claim["starttime"] < c["endtime"] and claim["endtime"] > c["starttime"] + overlap_in_time = claim["starttime"] < c["endtime"] and claim["endtime"] > c["starttime"] + overlap_in_resource = c["resource_id"] == resource_id if c["status"] != "conflict" and \ c["id"] != claim.get("id",None) and \ - c["resource_id"] == resource_id and \ - overlap: + overlap_in_resource and \ + overlap_in_time: usage += c["claim_size"] return usage + claim["claim_size"] <= self.resource_capacity @@ -399,8 +400,6 @@ class PrioritySchedulerTest(BasicSchedulerTest): def test_partial_conflict(self): """ Whether a task gets scheduled correctly if it has a partial conflict after the first fit. """ - logger.info("test_partial") - # First task must succeed self.new_task(0) estimates = [{ 'resource_types': {'bandwidth': 512} }, @@ -482,6 +481,28 @@ class DwellSchedulerTest(PrioritySchedulerTest): self.assertEqual(self.fake_ra_database.tasks[1]["starttime"], datetime.datetime(2017, 1, 1, 2, 0, 0)) self.assertEqual(self.fake_ra_database.tasks[1]["endtime"], datetime.datetime(2017, 1, 1, 3, 0, 0)) + def test_dwell_respect_claim_endtime(self): + """ Whether a dwelling task will honour the claim endtimes, instead of the task endtime. """ + + # First task must succeed + self.new_dwell_task(0) + estimates = [{ 'resource_types': {'bandwidth': 512} }] + allocation_succesful = self.scheduler.allocate_resources(estimates) + self.assertTrue(allocation_succesful) + + # Extend claim + self.fake_ra_database.claims[0][0]["endtime"] += datetime.timedelta(hours=1) + + # Second task must also succeed + self.new_dwell_task(1) + estimates = [{ 'resource_types': {'bandwidth': 513} }] + allocation_succesful = self.scheduler.allocate_resources(estimates) + self.assertTrue(allocation_succesful) + + # Second task must have been moved beyond claim endtime + self.assertEqual(self.fake_ra_database.tasks[1]["starttime"], datetime.datetime(2017, 1, 1, 3, 0, 0)) + self.assertEqual(self.fake_ra_database.tasks[1]["endtime"], datetime.datetime(2017, 1, 1, 4, 0, 0)) + if __name__ == '__main__': logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.DEBUG)