Example #1
0
 def start(self):
     """Start the process loop in a thread."""
     if self.thread.is_alive():
         return
     self.thread = StoppableThread(target=self.run,
                                   name=self.__class__.__name__ +
                                   timestamp())
     self.thread.start()
Example #2
0
 def __init__(self):
     self.thread = StoppableThread(
     )  # the thread the manager loop is running in
     self.lock = threading.Condition(
     )  # lock to control access to 'queue' and 'running'
     self.queue = []
     self.running = None
     self.refresh_interval = 0.1  # seconds
Example #3
0
class CronDaemon():
    __metaclass__ = Singleton

    def __init__(self, *events):
        self.events = list(events)
        self.lock = threading.Lock()
        self.thread = StoppableThread(
        )  # the thread the manager loop is running in

    def register(self, event):
        self.lock.acquire()
        try:
            self.events.append(event)
        finally:
            self.lock.release()

    def remove(self, event):
        self.lock.acquire()
        try:
            self.events.remove(event)
        finally:
            self.lock.release()

    def start(self):
        """Start the process loop in a thread."""
        if self.thread.is_alive():
            return
        self.thread = StoppableThread(target=self.run,
                                      name=self.__class__.__name__ +
                                      timestamp())
        self.thread.start()

    def stop(self, timeout=None):
        """Stop the process loop."""
        self.thread.stop(timeout=timeout)

    def run(self):
        logging.getLogger().info('Starting Cron Daemon.')
        t = datetime(*datetime.now().timetuple()[:5])
        while 1:

            self.lock.acquire()
            try:
                logging.getLogger().log(
                    5, 'Checking events at ' + str(datetime.now()) + ' with ' +
                    str(t) + '.')
                for e in self.events:
                    e.check(t)
            finally:
                self.lock.release()

            t += timedelta(minutes=1)
            while datetime.now() < t:
                delta = (t - datetime.now()).total_seconds()
                self.thread.stop_request.wait(delta)
                if self.thread.stop_request.isSet():
                    return
        logging.getLogger().info('Shutting down Cron Daemon.')
Example #4
0
 def start(self):
     """Start the process loop in a thread."""
     if self.thread.is_alive():
         return
     logging.getLogger().info('Starting Job Manager.')
     self.thread = StoppableThread(target=self._process,
                                   name=self.__class__.__name__ +
                                   timestamp())
     self.thread.start()
Example #5
0
 def __init__(self, *events):
     self.events = list(events)
     self.lock = threading.Lock()
     self.thread = StoppableThread() # the thread the manager loop is running in
Example #6
0
class Job(HasTraits):
    """
    Defines a job.
    
    Methods:
    
        start():        starts the job
        stop(timeout):  stops the job
        _run():         actual function that is run in a thread
        
    Data:
    
        priority:   priority of the job (used by a job manager to schedule the job)
        state:      shows the current state of the job, 'idle', 'run' or 'wait'
    
      In the current execution model, a job should be re-startable.
    I.e., when a job is stopped before it is finished, upon next
    start, the work should be continued e.g. previously acquired
    data should be kept and accumulated.
    
      It is the user's task to ensure that previous data is
    handled correctly and to decide when a job should be continued
    and when it should be restarted as a new measurement. 

      A job can be in one of three states 'idle': doing nothing,
    'run': running, 'wait': waiting to be executed. The latter state
    is typically set by a Job manager to show that the job is
    scheduled for execution. The  
    """

    priority = Range(low=0,
                     high=10,
                     value=0,
                     desc='priority of the job',
                     label='priority',
                     mode='text',
                     auto_set=False,
                     enter_set=True)

    state = Enum(
        'idle', 'run', 'wait', 'done', 'error'
    )  # only for display. Shows the state of the job. 'idle': not submitted, 'run': running, 'wait':in queue

    thread = Instance(StoppableThread, factory=StoppableThread)

    edit = Button(label='Show', desc='Show GUI.')
    close = Button(label='Hide', desc='Hide GUI.')

    def _edit_fired(self):
        """Show the default view (named traits_view)."""
        self.edit_traits()

    def start(self):
        """Start the thread."""
        if self.thread.is_alive():
            return
        self.thread = StoppableThread(target=self._run,
                                      name=self.__class__.__name__ +
                                      timestamp())
        self.thread.start()

    def stop(self, timeout=None):
        """Stop the thread."""
        self.thread.stop(timeout=timeout)

    def _run(self):
        """Method that is run in a thread."""
        try:
            self.state = 'run'
            while (True):
                #logging.getLogger().debug("Yeah, still taking data like the LHC!")
                self.thread.stop_request.wait(
                    1.0
                )  # little trick to have a long (1 s) refresh interval but still react immediately to a stop request
                if self.thread.stop_request.isSet():
                    logging.getLogger().debug(
                        'Received stop signal. Returning from thread.')
                    break
            if True:
                self.state = 'idle'
            else:
                self.state = 'done'
        except:
            logging.getLogger().exception('Error in job.')
            self.state = 'error'
        finally:
            logging.getLogger().debug('Turning off all instruments.')

    min_view = View(
        HGroup(
            HGroup(
                Item('edit', show_label=False),
                Item('close', show_label=False),
                show_border=True,
            ), ))
Example #7
0
class JobManager(
):  # ToDo: In principle this need not be a singleton. Then there could be different job managers handling different sets of resources. However currently we need singleton since the JobManager is called explicitly on ManagedJob class.
    __metaclass__ = Singleton
    """Provides a queue for starting and stopping jobs according to their priority."""
    def __init__(self):
        self.thread = StoppableThread(
        )  # the thread the manager loop is running in
        self.lock = threading.Condition(
        )  # lock to control access to 'queue' and 'running'
        self.queue = []
        self.running = None
        self.refresh_interval = 0.1  # seconds

    def submit(self, job):
        """
        Submit a job.
        
        If there is no job running, the job is appended to the queue.

        If the job is the running job or the job is already in the queue, do nothing.
        
        If job.priority =< priority of the running job,
            the job is appended to the queue and the queue sorted according to priority.
        
        If job.priority > priority of the running job,
            the job is inserted at the first position of the queue, the running job is stopped
            and inserted again at the first position of the queue.
        """

        logging.debug('Attempt to submit job ' + str(job))
        self.lock.acquire()

        running = self.running
        queue = self.queue

        if job is running or job in queue:
            logging.info('The job ' + str(job) +
                         ' is already running or in the queue.')
            self.lock.release()
            return

        queue.append(job)
        queue.sort(cmp=lambda x, y: cmp(x.priority, y.priority),
                   reverse=True)  # ToDo: Job sorting not thoroughly tested
        job.state = 'wait'

        logging.debug('Notifying process thread.')
        self.lock.notify()

        self.lock.release()
        logging.debug('Job ' + str(job) + ' submitted.')

    def remove(self, job):
        """
        Remove a job.
        
        If the job is running, stop it.
        
        If the job is in the queue, remove it.
        
        If the job is not found, this will result in an exception.
        """

        logging.debug('Attempt to remove job ' + str(job))
        self.lock.acquire()

        try:
            if job is self.running:
                logging.debug('Job ' + str(job) + ' is running. Attempt stop.')
                job.stop()
                logging.debug('Job ' + str(job) + ' removed.')
            else:
                if not job in self.queue:
                    logging.debug('Job ' + str(job) +
                                  ' neither running nor in queue. Returning.')
                else:
                    logging.debug('Job ' + str(job) +
                                  ' is in queue. Attempt remove.')
                    self.queue.remove(job)
                    logging.debug('Job ' + str(job) + ' removed.')
                    job.state = 'idle'  # ToDo: improve handling of state. Move handling to Job?
        finally:
            self.lock.release()

    def start(self):
        """Start the process loop in a thread."""
        if self.thread.is_alive():
            return
        logging.getLogger().info('Starting Job Manager.')
        self.thread = StoppableThread(target=self._process,
                                      name=self.__class__.__name__ +
                                      timestamp())
        self.thread.start()

    def stop(self, timeout=None):
        """Stop the process loop."""
        self.thread.stop_request.set()
        self.lock.acquire()
        self.lock.notify()
        self.lock.release()
        self.thread.stop(timeout=timeout)

    def _process(self):
        """
        The process loop.
        
        Use .start() and .stop() methods to start and stop processing of the queue.
        """

        while True:

            self.thread.stop_request.wait(self.refresh_interval)
            if self.thread.stop_request.isSet():
                break

            # ToDo: jobs can be in queue before process loop is started
            # what happens when manager is stopped while jobs are running?

            self.lock.acquire()
            if self.running is None:
                if self.queue == []:
                    logging.debug(
                        'No job running. No job in queue. Waiting for notification.'
                    )
                    self.lock.wait()
                    logging.debug('Caught notification.')
                    if self.thread.stop_request.isSet():
                        self.lock.release()
                        break
                logging.debug('Attempt to fetch first job in queue.')
                self.running = self.queue.pop(0)
                logging.debug('Found job ' + str(self.running) + '. Starting.')
                self.running.start()
            elif not self.running.thread.is_alive():
                print '\x07'  # beep
                logging.debug('Job ' + str(self.running) + ' stopped.')
                self.running = None
                if self.queue != []:
                    logging.debug('Attempt to fetch first job in queue.')
                    self.running = self.queue.pop(0)
                    logging.debug('Found job ' + str(self.running) +
                                  '. Starting.')
                    self.running.start()
            elif self.queue != [] and self.queue[
                    0].priority > self.running.priority:
                logging.debug(
                    'Found job ' + str(self.queue[0]) +
                    ' in queue with higher priority than running job. Attempt to stop running job.'
                )
                self.running.stop()
                if self.running.state != 'done':
                    logging.debug('Reinserting job ' + str(self.running) +
                                  ' in queue.')
                    self.queue.insert(0, self.running)
                    self.queue.sort(
                        cmp=lambda x, y: cmp(x.priority, y.priority),
                        reverse=True
                    )  # ToDo: Job sorting not thoroughly tested
                    self.running.state = 'wait'
                self.running = self.queue.pop(0)
                logging.debug('Found job ' + str(self.running) + '. Starting.')
                self.running.start()
            self.lock.release()