Skip to content
Snippets Groups Projects
Commit 5fb5ac97 authored by Jorrit Schaap's avatar Jorrit Schaap
Browse files

TMSS-190: first step towards stategy pattern

parent ce176ef1
No related branches found
No related tags found
1 merge request!252Resolve TMSS-190
...@@ -43,7 +43,9 @@ from lofar.sas.tmss.tmss.tmssapp.conversions import LOFAR_CENTER_OBSERVER, Time, ...@@ -43,7 +43,9 @@ from lofar.sas.tmss.tmss.tmssapp.conversions import LOFAR_CENTER_OBSERVER, Time,
def get_schedulable_scheduling_units() -> [models.SchedulingUnitBlueprint]: def get_schedulable_scheduling_units() -> [models.SchedulingUnitBlueprint]:
'''get a list of all schedulable scheduling_units''' '''get a list of all schedulable scheduling_units'''
defined_independend_subtasks = models.Subtask.independent_subtasks().filter(state__value='defined') defined_independend_subtasks = models.Subtask.independent_subtasks().filter(state__value='defined')
scheduling_units = models.SchedulingUnitBlueprint.objects.filter(id__in=defined_independend_subtasks.values('task_blueprint__scheduling_unit_blueprint_id').distinct()).all() defined_independend_subtask_ids = defined_independend_subtasks.values('task_blueprint__scheduling_unit_blueprint_id').distinct().all()
# TODO: prefetch related models, like draft, spec, templates, etc
scheduling_units = models.SchedulingUnitBlueprint.objects.filter(id__in=defined_independend_subtask_ids).all()
return [su for su in scheduling_units if su.status == 'schedulable'] return [su for su in scheduling_units if su.status == 'schedulable']
...@@ -56,37 +58,62 @@ def get_scheduled_scheduling_units(lower:datetime=None, upper:datetime=None) -> ...@@ -56,37 +58,62 @@ def get_scheduled_scheduling_units(lower:datetime=None, upper:datetime=None) ->
scheduled_subtasks = scheduled_subtasks.filter(start_time__lte=upper) scheduled_subtasks = scheduled_subtasks.filter(start_time__lte=upper)
return list(models.SchedulingUnitBlueprint.objects.filter(id__in=scheduled_subtasks.values('task_blueprint__scheduling_unit_blueprint_id').distinct()).all()) return list(models.SchedulingUnitBlueprint.objects.filter(id__in=scheduled_subtasks.values('task_blueprint__scheduling_unit_blueprint_id').distinct()).all())
def can_run_within_timewindow(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime, upper_bound: datetime) -> bool:
constraints_template = scheduling_unit.draft.scheduling_constraints_template
if constraints_template.name == 'constraints':
if constraints_template.version == 1:
return can_run_within_timewindow_template_constraints_1(scheduling_unit, lower_bound, upper_bound)
raise UnknownTemplateException("Cannot check if scheduling_unit id=%s can run between '%s' and '%s', because we have no constraint solver for scheduling constraints template '%s' version=%s" % (
scheduling_unit.id, lower_bound, upper_bound, constraints_template.name, constraints_template.version))
def can_run_within_timewindow_template_constraints_1(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime, upper_bound: datetime) -> bool:
constraints = scheduling_unit.draft.scheduling_constraints_doc
return can_run_within_timewindow_template_constraints_1_daily(scheduling_unit, lower_bound, upper_bound)
def can_run_within_timewindow_template_constraints_1_daily(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime, upper_bound: datetime) -> bool:
constraints = scheduling_unit.draft.scheduling_constraints_doc
if not (constraints['daily']['require_day'] and constraints['daily']['require_night']):
# no day/night restrictions, can run any time
return True
if constraints['daily']['require_day'] or constraints['daily']['require_night']:
# TODO: TMSS-254 and TMSS-255
# TODO: take avoid_twilight into account
# Please note that this first crude proof of concept treats sunset/sunrise as 'events',
# whereas in our definition they are transition periods. See: TMSS-435
# Ugly code. Should be improved. Works for demo.
# create a series of timestamps in the window of opportunity, and evaluate of there are all during day or night
possible_start_time = get_first_possible_start_time(scheduling_unit, lower_bound)
possible_stop_time = possible_start_time + scheduling_unit.duration
timestamps = [possible_start_time]
while timestamps[-1] < possible_stop_time - timedelta(hours=8):
timestamps.append(timestamps[-1] + timedelta(hours=8))
timestamps.append(possible_stop_time)
if constraints['daily']['require_night'] and all(LOFAR_CENTER_OBSERVER.is_night(timestamp) for timestamp in timestamps):
return True
if constraints['daily']['require_day'] and all(not LOFAR_CENTER_OBSERVER.is_night(timestamp) for timestamp in timestamps):
return True
return False
def filter_scheduling_units_using_constraints(scheduling_units:[models.SchedulingUnitBlueprint], lower_bound_start_time: datetime, upper_bound_stop_time: datetime) -> [models.SchedulingUnitBlueprint]: def filter_scheduling_units_using_constraints(scheduling_units:[models.SchedulingUnitBlueprint], lower_bound_start_time: datetime, upper_bound_stop_time: datetime) -> [models.SchedulingUnitBlueprint]:
filtered_scheduling_units = [] '''return the schedulable scheduling_units which for which the constraints are 'go' within the given timewindow'''
for scheduling_unit in scheduling_units:
constraints = scheduling_unit.draft.scheduling_constraints_doc def can_run_within_timewindow_no_exception(scheduling_unit, lower_bound, upper_bound):
try:
if not constraints: return can_run_within_timewindow(scheduling_unit, lower_bound, upper_bound)
# accept any scheduling_unit with no constraints except UnknownTemplateException as e:
filtered_scheduling_units.append(scheduling_unit) logger.warning(e)
continue return False
# TODO: use factory to get filter function based on scheduling_constraints_template and/or constraint name return [sub for sub in scheduling_units
# for now, assume there is only one template, allowing straightforward filtering. if can_run_within_timewindow_no_exception(sub, lower_bound_start_time, upper_bound_stop_time)]
if not (constraints['daily']['require_day'] and constraints['daily']['require_night']):
filtered_scheduling_units.append(scheduling_unit)
elif constraints['daily']['require_day'] or constraints['daily']['require_night']:
# TODO: take avoid_twilight into account
# Ugly code. Should be improved. Works for demo.
# create a series of timestamps in the window of opportunity, and evaluate of there are all during day or night
possible_start_time = get_first_possible_start_time(scheduling_unit, lower_bound_start_time)
possible_stop_time = possible_start_time + scheduling_unit.duration
timestamps = [possible_start_time]
while timestamps[-1] < possible_stop_time-timedelta(hours=8):
timestamps.append(timestamps[-1] + timedelta(hours=8))
timestamps.append(possible_stop_time)
if constraints['daily']['require_night'] and all(LOFAR_CENTER_OBSERVER.is_night(timestamp) for timestamp in timestamps):
filtered_scheduling_units.append(scheduling_unit)
elif constraints['daily']['require_day'] and all(not LOFAR_CENTER_OBSERVER.is_night(timestamp) for timestamp in timestamps):
filtered_scheduling_units.append(scheduling_unit)
return filtered_scheduling_units
def find_best_next_schedulable_unit(lower_bound_start_time: datetime=None, upper_bound_stop_time: datetime=None, scheduling_units:[models.SchedulingUnitBlueprint]=None) -> (models.SchedulingUnitBlueprint, datetime): def find_best_next_schedulable_unit(lower_bound_start_time: datetime=None, upper_bound_stop_time: datetime=None, scheduling_units:[models.SchedulingUnitBlueprint]=None) -> (models.SchedulingUnitBlueprint, datetime):
""" """
......
...@@ -22,3 +22,7 @@ class SubtaskSchedulingException(SchedulingException): ...@@ -22,3 +22,7 @@ class SubtaskSchedulingException(SchedulingException):
class TaskSchedulingException(SchedulingException): class TaskSchedulingException(SchedulingException):
pass pass
class UnknownTemplateException(TMSSException):
'''raised when TMSS trying to base its processing routines on the chosen template, but this specific template is unknown.'''
pass
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment