class_docstr: Task Scheduling controller.
  Notice time-zone is ALWAYS UTC
class_docstr_tok: ["Task","Scheduling","controller",".","Notice","time-zone","is","ALWAYS","UTC"]
docstr: Create a cron job-like scheduling for a pre-existing Task.
  Notice, it is recommended to give the schedule entry a descriptive unique name,
  if not provided, a name is randomly generated.
  
  When timespec parameters are specified exclusively, they define the time between task launches (see
  `year` and `weekdays` exceptions). When multiple timespec parameters are specified, the parameter representing
  the longest duration defines the time between task launches, and the shorter timespec parameters define specific
  times.
  
  Examples:
  
  Launch every 15 minutes
      add_task(schedule_task_id='1235', queue='default', minute=15)
  Launch every 1 hour
      add_task(schedule_task_id='1235', queue='default', hour=1)
  Launch every 1 hour at hour:30 minutes (i.e. 1:30, 2:30 etc.)
      add_task(schedule_task_id='1235', queue='default', hour=1, minute=30)
  Launch every day at 22:30 (10:30 pm)
      add_task(schedule_task_id='1235', queue='default', minute=30, hour=22, day=1)
  Launch every other day at 7:30 (7:30 am)
      add_task(schedule_task_id='1235', queue='default', minute=30, hour=7, day=2)
  Launch every Saturday at 8:30am (notice `day=0`)
      add_task(schedule_task_id='1235', queue='default', minute=30, hour=8, day=0, weekdays=['saturday'])
  Launch every 2 hours on the weekends Saturday/Sunday (notice `day` is not passed)
      add_task(schedule_task_id='1235', queue='default', hour=2, weekdays=['saturday', 'sunday'])
  Launch once a month at the 5th of each month
      add_task(schedule_task_id='1235', queue='default', month=1, day=5)
  Launch once a year on March 4th
      add_task(schedule_task_id='1235', queue='default', year=1, month=3, day=4)
  
  :param schedule_task_id: ID of Task to be cloned and scheduled for execution
  :param schedule_function: Optional, instead of providing Task ID to be scheduled,
      provide a function to be called. Notice the function is called from the scheduler context
      (i.e. running on the same machine as the scheduler)
  :param queue: Name or ID of queue to put the Task into (i.e. schedule)
  :param name: Name or description for the cron Task (should be unique if provided, otherwise randomly generated)
  :param target_project: Specify target project to put the cloned scheduled Task in.
  :param minute: Time (in minutes) between task launches. If specified together with `hour`, `day`, `month`,
      and / or  `year`, it defines the minute of the hour
  :param hour: Time (in hours) between task launches. If specified together with `day`, `month`, and / or
      `year`, it defines the hour of day.
  :param day: Time (in days) between task executions. If specified together with  `month` and / or `year`,
      it defines the day of month
  :param weekdays: Days of week to launch task (accepted inputs: 'monday', 'tuesday', 'wednesday',
      'thursday', 'friday', 'saturday', 'sunday')
  :param month: Time (in months) between task launches. If specified with `year`, it defines a specific month
  :param year: Specific year if value >= current year. Time (in years) between task launches if
      value <= 100
  :param limit_execution_time: Limit the execution time (in hours) of the specific job.
  :param single_instance: If True, do not launch the Task job if the previous instance is still running
      (skip until the next scheduled time period). Default False.
  :param recurring: If False, only launch the Task once (default: True, repeat)
  :param execute_immediately: If True, schedule the Task to be executed immediately
      then recurring based on the timing schedule arguments. Default False.
  :param reuse_task: If True, re-enqueue the same Task (i.e. do not clone it) every time, default False.
  :param task_parameters: Configuration parameters to the executed Task.
      for example: {'Args/batch': '12'} Notice: not available when reuse_task=True
  :param task_overrides: Change task definition.
      for example {'script.version_num': None, 'script.branch': 'main'} Notice: not available when reuse_task=True
  
  :return: True if job is successfully added to the scheduling list
docstr_tok: ["Create","a","cron","job-like","scheduling","for","a","pre-existing","Task",".","Notice",",","it","is","recommended","to","give","the","schedule","entry","a","descriptive","unique","name",",","if","not","provided",",","a","name","is","randomly","generated",".","When","timespec","parameters","are","specified","exclusively",",","they","define","the","time","between","task","launches","(","see","`","year","`","and","`","weekdays","`","exceptions",")",".","When","multiple","timespec","parameters","are","specified",",","the","parameter","representing","the","longest","duration","defines","the","time","between","task","launches",",","and","the","shorter","timespec","parameters","define","specific","times",".","Examples",":","Launch","every","15","minutes","add_task","(","schedule_task_id='1235","'",",","queue='default","'",",","minute=15",")","Launch","every","1","hour","add_task","(","schedule_task_id='1235","'",",","queue='default","'",",","hour=1",")","Launch","every","1","hour","at","hour:30","minutes","(","i.e",".","1:30",",","2:30","etc",".",")","add_task","(","schedule_task_id='1235","'",",","queue='default","'",",","hour=1",",","minute=30",")","Launch","every","day","at","22:30","(","10:30","pm",")","add_task","(","schedule_task_id='1235","'",",","queue='default","'",",","minute=30",",","hour=22",",","day=1",")","Launch","every","other","day","at","7:30","(","7:30","am",")","add_task","(","schedule_task_id='1235","'",",","queue='default","'",",","minute=30",",","hour=7",",","day=2",")","Launch","every","Saturday","at","8:30am","(","notice","`","day=0","`",")","add_task","(","schedule_task_id='1235","'",",","queue='default","'",",","minute=30",",","hour=8",",","day=0",",","weekdays=","[","'saturday","'","]",")","Launch","every","2","hours","on","the","weekends","Saturday\/Sunday","(","notice","`","day","`","is","not","passed",")","add_task","(","schedule_task_id='1235","'",",","queue='default","'",",","hour=2",",","weekdays=","[","'saturday","'",",","'sunday","'","]",")","Launch","once","a","month","at","the","5th","of","each","month","add_task","(","schedule_task_id='1235","'",",","queue='default","'",",","month=1",",","day=5",")","Launch","once","a","year","on","March","4th","add_task","(","schedule_task_id='1235","'",",","queue='default","'",",","year=1",",","month=3",",","day=4",")",":","param","schedule_task_id",":","ID","of","Task","to","be","cloned","and","scheduled","for","execution",":","param","schedule_function",":","Optional",",","instead","of","providing","Task","ID","to","be","scheduled",",","provide","a","function","to","be","called",".","Notice","the","function","is","called","from","the","scheduler","context","(","i.e",".","running","on","the","same","machine","as","the","scheduler",")",":","param","queue",":","Name","or","ID","of","queue","to","put","the","Task","into","(","i.e",".","schedule",")",":","param","name",":","Name","or","description","for","the","cron","Task","(","should","be","unique","if","provided",",","otherwise","randomly","generated",")",":","param","target_project",":","Specify","target","project","to","put","the","cloned","scheduled","Task","in",".",":","param","minute",":","Time","(","in","minutes",")","between","task","launches",".","If","specified","together","with","`","hour","`",",","`","day","`",",","`","month","`",",","and","\/","or","`","year","`",",","it","defines","the","minute","of","the","hour",":","param","hour",":","Time","(","in","hours",")","between","task","launches",".","If","specified","together","with","`","day","`",",","`","month","`",",","and","\/","or","`","year","`",",","it","defines","the","hour","of","day",".",":","param","day",":","Time","(","in","days",")","between","task","executions",".","If","specified","together","with","`","month","`","and","\/","or","`","year","`",",","it","defines","the","day","of","month",":","param","weekdays",":","Days","of","week","to","launch","task","(","accepted","inputs",":","'monday","'",",","'tuesday","'",",","'wednesday","'",",","'thursday","'",",","'friday","'",",","'saturday","'",",","'sunday","'",")",":","param","month",":","Time","(","in","months",")","between","task","launches",".","If","specified","with","`","year","`",",","it","defines","a","specific","month",":","param","year",":","Specific","year","if","value",">","=","current","year",".","Time","(","in","years",")","between","task","launches","if","value","<","=","100",":","param","limit_execution_time",":","Limit","the","execution","time","(","in","hours",")","of","the","specific","job",".",":","param","single_instance",":","If","True",",","do","not","launch","the","Task","job","if","the","previous","instance","is","still","running","(","skip","until","the","next","scheduled","time","period",")",".","Default","False",".",":","param","recurring",":","If","False",",","only","launch","the","Task","once","(","default",":","True",",","repeat",")",":","param","execute_immediately",":","If","True",",","schedule","the","Task","to","be","executed","immediately","then","recurring","based","on","the","timing","schedule","arguments",".","Default","False",".",":","param","reuse_task",":","If","True",",","re-enqueue","the","same","Task","(","i.e",".","do","not","clone","it",")","every","time",",","default","False",".",":","param","task_parameters",":","Configuration","parameters","to","the","executed","Task",".","for","example",":","{","'Args\/batch","'",":","'12","'","}","Notice",":","not","available","when","reuse_task=True",":","param","task_overrides",":","Change","task","definition",".","for","example","{","'script.version_num","'",":","None",",","'script.branch","'",":","'main","'","}","Notice",":","not","available","when","reuse_task=True",":","return",":","True","if","job","is","successfully","added","to","the","scheduling","list"]
code: def add_task(
      self,
      schedule_task_id=None,  # type: Union[str, Task]
      schedule_function=None,  # type: Callable
      queue=None,  # type: str
      name=None,  # type: Optional[str]
      target_project=None,  # type: Optional[str]
      minute=None,  # type: Optional[int]
      hour=None,  # type: Optional[int]
      day=None,  # type: Optional[int]
      weekdays=None,  # type: Optional[List[str]]
      month=None,  # type: Optional[int]
      year=None,  # type: Optional[int]
      limit_execution_time=None,  # type: Optional[float]
      single_instance=False,  # type: bool
      recurring=True,  # type: bool
      execute_immediately=False,  # type: bool
      reuse_task=False,  # type: bool
      task_parameters=None,  # type: Optional[dict]
      task_overrides=None,  # type: Optional[dict]
  ):
      # type: (...) -> bool
      """
      Create a cron job-like scheduling for a pre-existing Task.
      Notice, it is recommended to give the schedule entry a descriptive unique name,
      if not provided, a name is randomly generated.
  
      When timespec parameters are specified exclusively, they define the time between task launches (see
      `year` and `weekdays` exceptions). When multiple timespec parameters are specified, the parameter representing
      the longest duration defines the time between task launches, and the shorter timespec parameters define specific
      times.
  
      Examples:
  
      Launch every 15 minutes
          add_task(schedule_task_id='1235', queue='default', minute=15)
      Launch every 1 hour
          add_task(schedule_task_id='1235', queue='default', hour=1)
      Launch every 1 hour at hour:30 minutes (i.e. 1:30, 2:30 etc.)
          add_task(schedule_task_id='1235', queue='default', hour=1, minute=30)
      Launch every day at 22:30 (10:30 pm)
          add_task(schedule_task_id='1235', queue='default', minute=30, hour=22, day=1)
      Launch every other day at 7:30 (7:30 am)
          add_task(schedule_task_id='1235', queue='default', minute=30, hour=7, day=2)
      Launch every Saturday at 8:30am (notice `day=0`)
          add_task(schedule_task_id='1235', queue='default', minute=30, hour=8, day=0, weekdays=['saturday'])
      Launch every 2 hours on the weekends Saturday/Sunday (notice `day` is not passed)
          add_task(schedule_task_id='1235', queue='default', hour=2, weekdays=['saturday', 'sunday'])
      Launch once a month at the 5th of each month
          add_task(schedule_task_id='1235', queue='default', month=1, day=5)
      Launch once a year on March 4th
          add_task(schedule_task_id='1235', queue='default', year=1, month=3, day=4)
  
      :param schedule_task_id: ID of Task to be cloned and scheduled for execution
      :param schedule_function: Optional, instead of providing Task ID to be scheduled,
          provide a function to be called. Notice the function is called from the scheduler context
          (i.e. running on the same machine as the scheduler)
      :param queue: Name or ID of queue to put the Task into (i.e. schedule)
      :param name: Name or description for the cron Task (should be unique if provided, otherwise randomly generated)
      :param target_project: Specify target project to put the cloned scheduled Task in.
      :param minute: Time (in minutes) between task launches. If specified together with `hour`, `day`, `month`,
          and / or  `year`, it defines the minute of the hour
      :param hour: Time (in hours) between task launches. If specified together with `day`, `month`, and / or
          `year`, it defines the hour of day.
      :param day: Time (in days) between task executions. If specified together with  `month` and / or `year`,
          it defines the day of month
      :param weekdays: Days of week to launch task (accepted inputs: 'monday', 'tuesday', 'wednesday',
          'thursday', 'friday', 'saturday', 'sunday')
      :param month: Time (in months) between task launches. If specified with `year`, it defines a specific month
      :param year: Specific year if value >= current year. Time (in years) between task launches if
          value <= 100
      :param limit_execution_time: Limit the execution time (in hours) of the specific job.
      :param single_instance: If True, do not launch the Task job if the previous instance is still running
          (skip until the next scheduled time period). Default False.
      :param recurring: If False, only launch the Task once (default: True, repeat)
      :param execute_immediately: If True, schedule the Task to be executed immediately
          then recurring based on the timing schedule arguments. Default False.
      :param reuse_task: If True, re-enqueue the same Task (i.e. do not clone it) every time, default False.
      :param task_parameters: Configuration parameters to the executed Task.
          for example: {'Args/batch': '12'} Notice: not available when reuse_task=True
      :param task_overrides: Change task definition.
          for example {'script.version_num': None, 'script.branch': 'main'} Notice: not available when reuse_task=True
  
      :return: True if job is successfully added to the scheduling list
      """
      mutually_exclusive(
          schedule_function=schedule_function,
          schedule_task_id=schedule_task_id,
      )
      task_id = (
          schedule_task_id.id
          if isinstance(schedule_task_id, Task)
          else str(schedule_task_id or "")
      )
  
      # noinspection PyProtectedMember
      job = ScheduleJob(
          name=name or task_id,
          base_task_id=task_id,
          base_function=schedule_function,
          queue=queue,
          target_project=target_project,
          execution_limit_hours=limit_execution_time,
          recurring=bool(recurring),
          single_instance=bool(single_instance),
          task_parameters=task_parameters,
          task_overrides=task_overrides,
          clone_task=not bool(reuse_task),
          starting_time=datetime.fromtimestamp(0)
          if execute_immediately
          else datetime.utcnow(),
          minute=minute,
          hour=hour,
          day=day,
          weekdays=weekdays,
          month=month,
          year=year,
      )
      # raise exception if not valid
      job.verify()
  
      self._schedule_jobs.append(job)
      return True
  
imports: import json
  import logging
  from datetime import datetime
  from threading import Thread, enumerate
  from time import sleep, time
  from typing import List, Union, Optional, Callable, Sequence, Dict
  from attr import attrs, attrib
  from dateutil.relativedelta import relativedelta
  from .job import ClearmlJob
  from .controller import PipelineController
  from ..backend_interface.util import datetime_from_isoformat, datetime_to_isoformat, mutually_exclusive
  from ..task import Task
label_desc: Use image node_id 2 for calling the TaskScheduler obj's underlying member method code with example usage: obj.add_task(schedule_task_id, schedule_function, queue, name, target_project, minute, hour, day, weekdays, month, year, limit_execution_time, single_instance, recurring, execute_immediately, reuse_task, task_parameters, task_overrides) and returns: True