Beispiel #1
0
    def _updateProgress(self, job, total, current, message, notify, user,
                        updates):
        """Helper for updating job progress information."""
        state = JobStatus.toNotificationStatus(job['status'])

        if current is not None:
            current = float(current)
        if total is not None:
            total = float(total)

        if job['progress'] is None:
            if notify and job['userId']:
                notification = self._createProgressNotification(
                    job, total, current, state, message)
                notificationId = notification['_id']
            else:
                notificationId = None
            job['progress'] = {
                'message': message,
                'total': total,
                'current': current,
                'notificationId': notificationId
            }
            updates['$set']['progress'] = job['progress']
        else:
            if total is not None:
                job['progress']['total'] = total
                updates['$set']['progress.total'] = total
            if current is not None:
                job['progress']['current'] = current
                updates['$set']['progress.current'] = current
            if message is not None:
                job['progress']['message'] = message
                updates['$set']['progress.message'] = message

            if notify and user:
                if job['progress']['notificationId'] is None:
                    notification = self._createProgressNotification(
                        job, total, current, state, message, user)
                    nid = notification['_id']
                    job['progress']['notificationId'] = nid
                    updates['$set']['progress.notificationId'] = nid
                else:
                    notification = Notification().load(
                        job['progress']['notificationId'])

                Notification().updateProgress(
                    notification,
                    state=state,
                    message=job['progress']['message'],
                    current=job['progress']['current'],
                    total=job['progress']['total'])
Beispiel #2
0
    def __init__(self, on, interval=0.5, **kwargs):
        self.on = on
        self.interval = interval

        if on:
            self._lastSave = time.time()
            self.progress = Notification().initProgress(**kwargs)
Beispiel #3
0
 def _createUpdateStatusNotification(self, now, user, job):
     expires = now + datetime.timedelta(seconds=30)
     filtered = self.filter(job, user)
     filtered.pop('kwargs', None)
     filtered.pop('log', None)
     Notification().createNotification(type='job_status',
                                       data=filtered,
                                       user=user,
                                       expires=expires)
Beispiel #4
0
 def _updateLog(self, job, log, overwrite, now, notify, user, updates):
     """Helper for updating a job's log."""
     if overwrite:
         updates['$set']['log'] = [log]
     else:
         updates['$push']['log'] = log
     if notify and user:
         expires = now + datetime.timedelta(seconds=30)
         Notification().createNotification(type='job_log',
                                           data={
                                               '_id': job['_id'],
                                               'overwrite': overwrite,
                                               'text': log
                                           },
                                           user=user,
                                           expires=expires)
Beispiel #5
0
 def _createProgressNotification(self,
                                 job,
                                 total,
                                 current,
                                 state,
                                 message,
                                 user=None):
     if not user:
         user = User().load(job['userId'], force=True)
     # TODO support channel-based notifications for jobs. For
     # right now we'll just go through the user.
     return Notification().initProgress(user,
                                        job['title'],
                                        total,
                                        state=state,
                                        current=current,
                                        message=message,
                                        estimateTime=False,
                                        resource=job,
                                        resourceName=self.name)
Beispiel #6
0
    def update(self, force=False, **kwargs):
        """
        Update the underlying progress record. This will only actually save
        to the database if at least self.interval seconds have passed since
        the last time the record was written to the database. Accepts the
        same kwargs as Notification.updateProgress.

        :param force: Whether we should force the write to the database. Use
            only in cases where progress may be indeterminate for a long time.
        :type force: bool
        """
        # Extend the response timeout, even if we aren't reporting the progress
        setResponseTimeLimit()
        if not self.on:
            return
        save = (time.time() - self._lastSave > self.interval) or force
        self.progress = Notification().updateProgress(self.progress, save,
                                                      **kwargs)

        if save:
            self._lastSave = time.time()
Beispiel #7
0
    def __exit__(self, excType, excValue, traceback):
        """
        Once the context is exited, the progress is marked for deletion 30
        seconds in the future, which should give all listeners time to poll and
        receive the final state of the progress record before it is deleted.
        """
        if not self.on:
            return

        if excType is None and excValue is None:
            state = ProgressState.SUCCESS
            message = 'Done'
        else:
            state = ProgressState.ERROR
            message = 'Error'
            if isinstance(excValue, (ValidationException, RestException)):
                message = 'Error: ' + str(excValue)

        Notification().updateProgress(self.progress,
                                      state=state,
                                      message=message,
                                      expires=datetime.datetime.utcnow() +
                                      datetime.timedelta(seconds=30))
Beispiel #8
0
    def createJob(self,
                  title,
                  type,
                  args=(),
                  kwargs=None,
                  user=None,
                  when=None,
                  interval=0,
                  public=False,
                  handler=None,
                  asynchronous=False,
                  save=True,
                  parentJob=None,
                  otherFields=None):
        """
        Create a new job record.

        :param title: The title of the job.
        :type title: str
        :param type: The type of the job.
        :type type: str
        :param args: Positional args of the job payload.
        :type args: list or tuple
        :param kwargs: Keyword arguments of the job payload.
        :type kwargs: dict
        :param user: The user creating the job.
        :type user: dict or None
        :param when: Minimum start time for the job (UTC).
        :type when: datetime
        :param interval: If this job should be recurring, set this to a value
            in seconds representing how often it should occur. Set to <= 0 for
            jobs that should only be run once.
        :type interval: int
        :param public: Public read access flag.
        :type public: bool
        :param handler: If this job should be handled by a specific handler,
            use this field to store that information.
        :param externalToken: If an external token was created for updating this
        job, pass it in and it will have the job-specific scope set.
        :type externalToken: token (dict) or None.
        :param asynchronous: Whether the job is to be run asynchronously. For now this
            only applies to jobs that are scheduled to run locally.
        :type asynchronous: bool
        :param save: Whether the documented should be saved to the database.
        :type save: bool
        :param parentJob: The job which will be set as a parent
        :type parentJob: Job
        :param otherFields: Any additional fields to set on the job.
        :type otherFields: dict
        """
        now = datetime.datetime.utcnow()

        if when is None:
            when = now

        if kwargs is None:
            kwargs = {}

        otherFields = otherFields or {}
        parentId = None
        if parentJob:
            parentId = parentJob['_id']
        job = {
            'title': title,
            'type': type,
            'args': args,
            'kwargs': kwargs,
            'created': now,
            'updated': now,
            'when': when,
            'interval': interval,
            'status': JobStatus.INACTIVE,
            'progress': None,
            'log': [],
            'meta': {},
            'handler': handler,
            'asynchronous': asynchronous,
            'timestamps': [],
            'parentId': parentId
        }

        job.update(otherFields)

        self.setPublic(job, public=public)

        if user:
            job['userId'] = user['_id']
            self.setUserAccess(job, user=user, level=AccessType.ADMIN)
        else:
            job['userId'] = None

        if save:
            job = self.save(job)
        if user:
            deserialized_kwargs = job['kwargs']
            job['kwargs'] = json_util.dumps(job['kwargs'])

            Notification().createNotification(
                type='job_created',
                data=job,
                user=user,
                expires=datetime.datetime.utcnow() +
                datetime.timedelta(seconds=30))

            job['kwargs'] = deserialized_kwargs

        return job