Skip to content

jobqueue: Thread safety fixes #977

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 11 additions & 20 deletions telegram/ext/jobqueue.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class JobQueue(object):
"""This class allows you to periodically perform tasks with the bot.

Attributes:
queue (:obj:`PriorityQueue`): The queue that holds the Jobs.
_queue (:obj:`PriorityQueue`): The queue that holds the Jobs.
bot (:class:`telegram.Bot`): Bot that's send to the handlers.

Args:
Expand All @@ -54,7 +54,7 @@ def __init__(self, bot, prevent_autostart=None):
if prevent_autostart is not None:
warnings.warn("prevent_autostart is being deprecated, use `start` method instead.")

self.queue = PriorityQueue()
self._queue = PriorityQueue()
self.bot = bot
self.logger = logging.getLogger(self.__class__.__name__)
self.__start_lock = Lock()
Expand Down Expand Up @@ -88,7 +88,6 @@ def put(self, job, next_t=None):
tomorrow.

"""

warnings.warn("'JobQueue.put' is being deprecated, use 'JobQueue.run_once', "
"'JobQueue.run_daily' or 'JobQueue.run_repeating' instead")
if job.job_queue is None:
Expand Down Expand Up @@ -119,7 +118,7 @@ def _put(self, job, next_t=None, last_t=None):

self.logger.debug('Putting job %s with t=%f', job.name, next_t)

self.queue.put((next_t, job))
self._queue.put((next_t, job))

# Wake up the loop if this job should be executed next
self._set_next_peek(next_t)
Expand Down Expand Up @@ -196,7 +195,6 @@ def run_repeating(self, callback, interval, first=None, context=None, name=None)
queue.

"""

job = Job(callback,
interval=interval,
repeat=True,
Expand Down Expand Up @@ -227,7 +225,6 @@ def run_daily(self, callback, time, days=Days.EVERY_DAY, context=None, name=None
queue.

"""

job = Job(callback,
interval=datetime.timedelta(days=1),
repeat=True,
Expand All @@ -250,14 +247,13 @@ def _set_next_peek(self, t):

def tick(self):
"""Run all jobs that are due and re-enqueue them with their interval."""

now = time.time()

self.logger.debug('Ticking jobs with t=%f', now)

while True:
try:
t, job = self.queue.get(False)
t, job = self._queue.get(False)
except Empty:
break

Expand All @@ -270,7 +266,7 @@ def tick(self):
# 2. At the first iteration of the loop only if `self.put()` had triggered
# `self.__tick` because `self._next_peek` wasn't set
self.logger.debug("Next task isn't due yet. Finished!")
self.queue.put((t, job))
self._queue.put((t, job))
self._set_next_peek(t)
break

Expand Down Expand Up @@ -298,7 +294,6 @@ def tick(self):

def start(self):
"""Starts the job_queue thread."""

self.__start_lock.acquire()

if not self._running:
Expand Down Expand Up @@ -335,7 +330,6 @@ def _main_loop(self):

def stop(self):
"""Stops the thread."""

with self.__start_lock:
self._running = False

Expand All @@ -345,8 +339,8 @@ def stop(self):

def jobs(self):
"""Returns a tuple of all jobs that are currently in the ``JobQueue``."""

return tuple(job[1] for job in self.queue.queue if job)
with self._queue.mutex:
return tuple(job[1] for job in self._queue.queue if job)


class Job(object):
Expand Down Expand Up @@ -407,7 +401,6 @@ def __init__(self,

def run(self, bot):
"""Executes the callback function."""

self.callback(bot, self)

def schedule_removal(self):
Expand All @@ -416,7 +409,6 @@ def schedule_removal(self):
its callback function again.

"""

self._remove.set()

@property
Expand Down Expand Up @@ -459,10 +451,11 @@ def interval(self, interval):
@property
def interval_seconds(self):
""":obj:`int`: The interval for this job in seconds."""
if isinstance(self.interval, datetime.timedelta):
return self.interval.total_seconds()
interval = self.interval
if isinstance(interval, datetime.timedelta):
return interval.total_seconds()
else:
return self.interval
return interval

@property
def repeat(self):
Expand All @@ -478,7 +471,6 @@ def repeat(self, repeat):
@property
def days(self):
"""Tuple[:obj:`int`]: Optional. Defines on which days of the week the job should run."""

return self._days

@days.setter
Expand All @@ -498,7 +490,6 @@ def days(self, days):
@property
def job_queue(self):
""":class:`telegram.ext.JobQueue`: Optional. The ``JobQueue`` this job belongs to."""

return self._job_queue

@job_queue.setter
Expand Down
4 changes: 2 additions & 2 deletions tests/test_jobqueue.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ def test_time_unit_dt_time_tomorrow(self, job_queue):
expected_time = time.time() + delta + 60 * 60 * 24

job_queue.run_once(self.job_datetime_tests, when)
assert pytest.approx(job_queue.queue.get(False)[0]) == expected_time
assert pytest.approx(job_queue._queue.get(False)[0]) == expected_time

def test_run_daily(self, job_queue):
delta = 0.5
Expand All @@ -212,7 +212,7 @@ def test_run_daily(self, job_queue):
job_queue.run_daily(self.job_run_once, time_of_day)
sleep(0.6)
assert self.result == 1
assert pytest.approx(job_queue.queue.get(False)[0]) == expected_time
assert pytest.approx(job_queue._queue.get(False)[0]) == expected_time

def test_warnings(self, job_queue):
j = Job(self.job_run_once, repeat=False)
Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy