def test_pass_in_schedule(self): schedule = pickle.dumps(CelerySchedule(60)) call = ScheduledCall('PT1M', 'pulp.tasks.dosomething', schedule=schedule) self.assertEqual(call.schedule, schedule)
def update(schedule_id, delta): """ Updates the schedule with unique ID schedule_id. This only allows updating of fields in ScheduledCall.USER_UPDATE_FIELDS. :param schedule_id: a unique ID for a schedule :type schedule_id: basestring :param delta: a dictionary of keys with values that should be modified on the schedule. :type delta: dict :return: instance of ScheduledCall representing the post-update state :rtype ScheduledCall :raise exceptions.UnsupportedValue :raise exceptions.MissingResource """ unknown_keys = set(delta.keys()) - ScheduledCall.USER_UPDATE_FIELDS if unknown_keys: raise exceptions.UnsupportedValue(list(unknown_keys)) delta['last_updated'] = time.time() # bz 1139703 - if we update iso_schedule, update the pickled object as well if 'iso_schedule' in delta: interval, start_time, occurrences = dateutils.parse_iso8601_interval( delta['iso_schedule']) delta['schedule'] = pickle.dumps(CelerySchedule(interval)) # set first_run and next_run so that the schedule update will take effect new_schedule_call = ScheduledCall(delta['iso_schedule'], 'dummytaskname') delta['first_run'] = new_schedule_call.first_run delta['next_run'] = new_schedule_call.next_run try: spec = {'_id': ObjectId(schedule_id)} except InvalidId: # During schedule update, MissingResource should be raised even if # schedule_id is invalid object_id. raise exceptions.MissingResource(schedule_id=schedule_id) schedule = ScheduledCall.get_collection().find_and_modify( query=spec, update={'$set': delta}, safe=True, new=True) if schedule is None: raise exceptions.MissingResource(schedule_id=schedule_id) return ScheduledCall.from_db(schedule)
def __init__(self, iso_schedule, task, total_run_count=0, next_run=None, schedule=None, args=None, kwargs=None, principal=None, last_updated=None, consecutive_failures=0, enabled=True, failure_threshold=None, last_run_at=None, first_run=None, remaining_runs=None, id=None, tags=None, name=None, options=None, resource=None): """ :param iso_schedule: string representing the schedule in ISO8601 format :type iso_schedule: basestring :param task: the task that should be run on a schedule. This can be an instance of a celery task or the name of the task, as taken from a task's "name" attribute :type task: basestring or celery.Task :param total_run_count: total number of times this schedule has run :type total_run_count: int :param next_run: ignored, because it is always re-calculated at instantiation :param schedule: pickled instance of celery.schedules.schedule, representing the schedule that should be run. This is optional. :type schedule: basestring or None :param args: list of arguments that should be passed to the task's apply_async function as its "args" argument :type args: list :param kwargs: dict of keyword arguments that should be passed to the task's apply_async function as its "kwargs" argument :type kwargs: dict :param principal: pickled instance of pulp.server.db.model.auth.User representing the pulp user who the task should be run as. This is optional. :type principal: basestring or None :param last_updated: timestamp for the last time this schedule was updated in the database as seconds since the epoch :type last_updated: float :param consecutive_failures: number of times this task has failed consecutively. This gets reset to zero if the task succeeds. :type consecutive_failures: int :param enabled: boolean indicating whether this schedule should be actively run by the scheduler. If False, the schedule will be ignored. :type enabled: bool :param failure_threshold: number of consecutive failures after which this task should be automatically disabled. Because these tasks run asynchronously, they may finish in a different order than they were queued in. Thus, it is possible that n consecutive failures will be reported by jobs that were not queued consecutively. So do not depend on the queuing order when using this feature. If this value is 0, no automatic disabling will occur. :type failure_threshold: int :param last_run_at: ISO8601 string representing when this schedule last ran. :type last_run_at: basestring :param first_run: ISO8601 string or datetime instance (in UTC timezone) representing when this schedule should run or should have been run for the first time. If the schedule has a specified date and time to start, this will be that value. If not, the value from the first time the schedule was actually run will be used. :type first_run: basestring or datetime.datetime or NoneType :param remaining_runs: number of runs remaining until this schedule will be automatically disabled. :type remaining_runs: int or NoneType :param id: unique ID used by mongodb to identify this schedule :type id: basestring :param tags: ignored, but allowed to exist as historical data for now :param name: ignored, because the "id" value is used for this now. The value is here for backward compatibility. :param options: dictionary that should be passed to the apply_async function as its "options" argument. :type options: dict :param resource: optional string indicating a unique resource that should be used to find this schedule. For example, to find all schedules for a given repository, a resource string will be derived for that repo, and this collection will be searched for that resource string. :type resource: basestring """ if id is None: # this creates self._id and self.id super(ScheduledCall, self).__init__() self._new = True else: self.id = id self._id = ObjectId(id) self._new = False if hasattr(task, 'name'): task = task.name # generate this if it wasn't passed in if schedule is None: interval, start_time, occurrences = dateutils.parse_iso8601_interval( iso_schedule) schedule = pickle.dumps(CelerySchedule(interval)) # generate this if it wasn't passed in principal = principal or factory.principal_manager().get_principal() self.args = args or [] self.consecutive_failures = consecutive_failures self.enabled = enabled self.failure_threshold = failure_threshold self.iso_schedule = iso_schedule self.kwargs = kwargs or {} self.last_run_at = last_run_at self.last_updated = last_updated or time.time() self.name = id self.options = options or {} self.principal = principal self.resource = resource self.schedule = schedule self.task = task self.total_run_count = total_run_count if first_run is None: # get the date and time from the iso_schedule value, and if it does not have a date and # time, use the current date and time self.first_run = dateutils.format_iso8601_datetime( dateutils.parse_iso8601_interval(iso_schedule)[1] or datetime.utcnow().replace(tzinfo=isodate.UTC)) elif isinstance(first_run, datetime): self.first_run = dateutils.format_iso8601_datetime(first_run) else: self.first_run = first_run if remaining_runs is None: self.remaining_runs = dateutils.parse_iso8601_interval( iso_schedule)[2] else: self.remaining_runs = remaining_runs self.next_run = self.calculate_next_run()