Exemple #1
0
 def clear_jobs(self):
     """Clear current Job queue and start fresh."""
     if self._jobs.empty():
         # Guards against getting stuck waiting for self._mutex when
         # thread is waiting for self._jobs to not be empty.
         return
     with self._mutex:
         self._cleared = True
         self._jobs = PriorityQueue()
Exemple #2
0
 def __init__(self, bot):
     """Requires bot as argument for logging."""
     threading.Thread.__init__(self)
     self.bot = bot
     self._jobs = PriorityQueue()
     # While PriorityQueue it self is thread safe, this mutex is needed
     # to stop old jobs being put into new queue after clearing the
     # queue.
     self._mutex = threading.Lock()
     # self.cleared is used for more fine grained locking.
     self._cleared = False
Exemple #3
0
 def clear_jobs(self):
     """Clear current Job queue and start fresh."""
     if self._jobs.empty():
         # Guards against getting stuck waiting for self._mutex when
         # thread is waiting for self._jobs to not be empty.
         return
     with self._mutex:
         self._cleared = True
         self._jobs = PriorityQueue()
Exemple #4
0
 def __init__(self, bot):
     """Requires bot as argument for logging."""
     threading.Thread.__init__(self)
     self.bot = bot
     self._jobs = PriorityQueue()
     # While PriorityQueue it self is thread safe, this mutex is needed
     # to stop old jobs being put into new queue after clearing the
     # queue.
     self._mutex = threading.Lock()
     # self.cleared is used for more fine grained locking.
     self._cleared = False
Exemple #5
0
    class JobScheduler(threading.Thread):

        """Calls jobs assigned to it in steady intervals.

        JobScheduler is a thread that keeps track of Jobs and calls them every
        X seconds, where X is a property of the Job. It maintains jobs in a
        priority queue, where the next job to be called is always the first
        item.
        Thread safety is maintained with a mutex that is released during long
        operations, so methods add_job and clear_jobs can be safely called from
        the main thread.

        """

        min_reaction_time = 30.0  # seconds
        """How often should scheduler checks for changes in the job list."""

        def __init__(self, bot):
            """Requires bot as argument for logging."""
            threading.Thread.__init__(self)
            self.bot = bot
            self._jobs = PriorityQueue()
            # While PriorityQueue it self is thread safe, this mutex is needed
            # to stop old jobs being put into new queue after clearing the
            # queue.
            self._mutex = threading.Lock()
            # self.cleared is used for more fine grained locking.
            self._cleared = False

        def add_job(self, job):
            """Add a Job to the current job queue."""
            self._jobs.put(job)

        def clear_jobs(self):
            """Clear current Job queue and start fresh."""
            if self._jobs.empty():
                # Guards against getting stuck waiting for self._mutex when
                # thread is waiting for self._jobs to not be empty.
                return
            with self._mutex:
                self._cleared = True
                self._jobs = PriorityQueue()

        def run(self):
            """Run forever."""
            while True:
                try:
                    self._do_next_job()
                except Exception:
                    # Modules exceptions are caught earlier, so this is a bit
                    # more serious. Options are to either stop the main thread
                    # or continue this thread and hope that it won't happen
                    # again.
                    self.bot.error()
                    # Sleep a bit to guard against busy-looping and filling
                    # the log with useless error messages.
                    time.sleep(10.0)  # seconds

        def _do_next_job(self):
            """Wait until there is a job and do it."""
            with self._mutex:
                # Wait until the next job should be executed.
                # This has to be a loop, because signals stop time.sleep().
                while True:
                    job = self._jobs.peek()
                    difference = job.next_time - time.time()
                    duration = min(difference, self.min_reaction_time)
                    if duration <= 0:
                        break
                    with released(self._mutex):
                        time.sleep(duration)

                self._cleared = False
                job = self._jobs.get()
                with released(self._mutex):
                    if job.func.thread:
                        t = threading.Thread(
                            target=self._call, args=(job.func,)
                        )
                        t.start()
                    else:
                        self._call(job.func)
                    job.next()
                # If jobs were cleared during the call, don't put an old job
                # into the new job queue.
                if not self._cleared:
                    self._jobs.put(job)

        def _call(self, func):
            """Wrapper for collecting errors from modules."""
            # Willie.bot.call is way too specialized to be used instead.
            try:
                func(self.bot)
            except Exception:
                self.bot.error()
Exemple #6
0
    class JobScheduler(threading.Thread):
        """Calls jobs assigned to it in steady intervals.

        JobScheduler is a thread that keeps track of Jobs and calls them every
        X seconds, where X is a property of the Job. It maintains jobs in a
        priority queue, where the next job to be called is always the first
        item.
        Thread safety is maintained with a mutex that is released during long
        operations, so methods add_job and clear_jobs can be safely called from
        the main thread.

        """

        min_reaction_time = 30.0  # seconds
        """How often should scheduler checks for changes in the job list."""
        def __init__(self, bot):
            """Requires bot as argument for logging."""
            threading.Thread.__init__(self)
            self.bot = bot
            self._jobs = PriorityQueue()
            # While PriorityQueue it self is thread safe, this mutex is needed
            # to stop old jobs being put into new queue after clearing the
            # queue.
            self._mutex = threading.Lock()
            # self.cleared is used for more fine grained locking.
            self._cleared = False

        def add_job(self, job):
            """Add a Job to the current job queue."""
            self._jobs.put(job)

        def clear_jobs(self):
            """Clear current Job queue and start fresh."""
            if self._jobs.empty():
                # Guards against getting stuck waiting for self._mutex when
                # thread is waiting for self._jobs to not be empty.
                return
            with self._mutex:
                self._cleared = True
                self._jobs = PriorityQueue()

        def run(self):
            """Run forever."""
            while True:
                try:
                    self._do_next_job()
                except Exception:
                    # Modules exceptions are caught earlier, so this is a bit
                    # more serious. Options are to either stop the main thread
                    # or continue this thread and hope that it won't happen
                    # again.
                    self.bot.error()
                    # Sleep a bit to guard against busy-looping and filling
                    # the log with useless error messages.
                    time.sleep(10.0)  # seconds

        def _do_next_job(self):
            """Wait until there is a job and do it."""
            with self._mutex:
                # Wait until the next job should be executed.
                # This has to be a loop, because signals stop time.sleep().
                while True:
                    job = self._jobs.peek()
                    difference = job.next_time - time.time()
                    duration = min(difference, self.min_reaction_time)
                    if duration <= 0:
                        break
                    with released(self._mutex):
                        time.sleep(duration)

                self._cleared = False
                job = self._jobs.get()
                with released(self._mutex):
                    if job.func.thread:
                        t = threading.Thread(target=self._call,
                                             args=(job.func, ))
                        t.start()
                    else:
                        self._call(job.func)
                    job.next()
                # If jobs were cleared during the call, don't put an old job
                # into the new job queue.
                if not self._cleared:
                    self._jobs.put(job)

        def _call(self, func):
            """Wrapper for collecting errors from modules."""
            # Willie.bot.call is way too specialized to be used instead.
            try:
                func(self.bot)
            except Exception:
                self.bot.error()