2323import warnings
2424import datetime
2525from numbers import Number
26- from threading import Thread , Lock , RLock , Event
26+ from threading import Thread , Lock , Event
2727from queue import PriorityQueue , Empty
2828
29- from telegram .utils .promise import Promise
30-
3129
3230class Days (object ):
3331 MON , TUE , WED , THU , FRI , SAT , SUN = range (7 )
@@ -58,7 +56,6 @@ def __init__(self, bot, prevent_autostart=None):
5856 self .logger = logging .getLogger (self .__class__ .__name__ )
5957 self .__start_lock = Lock ()
6058 self .__next_peek_lock = Lock () # to protect self._next_peek & self.__tick
61- self .__queue_lock = RLock () # to protect self.queue
6259 self .__tick = Event ()
6360 self .__thread = None
6461 """:type: Thread"""
@@ -132,8 +129,7 @@ def _put(self, job, next_t=None, last_t=None):
132129
133130 self .logger .debug ('Putting job %s with t=%f' , job .name , next_t )
134131
135- with self .__queue_lock :
136- self .queue .put ((next_t , job ))
132+ self .queue .put ((next_t , job ))
137133
138134 # Wake up the loop if this job should be executed next
139135 self ._set_next_peek (next_t )
@@ -227,47 +223,6 @@ def daily_job(self, callback, time, days=Days.EVERY_DAY, context=None, name=None
227223 self ._put (job , next_t = time )
228224 return job
229225
230- def update_job_due_time (self , job , due ):
231- """
232- Changes the due time of a job.
233-
234- Args:
235- job (Job): The job of which the due time should be changed. Must already exist in the
236- queue.
237- due (float): The new due time as a timestamp
238-
239- Returns:
240- float: The old due time of the job as a timestamp
241- """
242-
243- with self .__queue_lock :
244- cache = list ()
245- # Pop jobs from the priority queue one by one and check if it's the one we need.
246- # All other jobs are stashed away in the 'cache' list. Once the right job is found,
247- # it's put back into the queue with the new due time, together with all cached jobs.
248- try :
249- while True :
250- due_test , job_test = self .queue .get (block = False )
251-
252- if job_test is job :
253- self .queue .put ((due , job_test ))
254- old_due = due_test
255- break
256-
257- else :
258- cache .append ((due_test , job_test ))
259-
260- except Empty :
261- raise ValueError ("Specified 'job' doesn't exist in the job queue" )
262-
263- finally :
264- for item in reversed (cache ):
265- self .queue .put (item )
266-
267- # Make sure the queue wakes up if the updated due time requires it
268- self ._set_next_peek (due )
269- return old_due
270-
271226 def _set_next_peek (self , t ):
272227 """
273228 Set next peek if not defined or `t` is before next peek.
@@ -283,56 +238,55 @@ def tick(self):
283238 Run all jobs that are due and re-enqueue them with their interval.
284239
285240 """
286- with self .__queue_lock :
287- now = time .time ()
241+ now = time .time ()
288242
289- self .logger .debug ('Ticking jobs with t=%f' , now )
243+ self .logger .debug ('Ticking jobs with t=%f' , now )
290244
291- while True :
245+ while True :
246+ try :
247+ t , job = self .queue .get (False )
248+
249+ except Empty :
250+ break
251+
252+ self .logger .debug ('Peeked at %s with t=%f' , job .name , t )
253+
254+ if t > now :
255+ # We can get here in two conditions:
256+ # 1. At the second or later pass of the while loop, after we've already
257+ # processed the job(s) we were supposed to at this time.
258+ # 2. At the first iteration of the loop only if `self.put()` had triggered
259+ # `self.__tick` because `self._next_peek` wasn't set
260+ self .logger .debug ("Next task isn't due yet. Finished!" )
261+ self .queue .put ((t , job ))
262+ self ._set_next_peek (t )
263+ break
264+
265+ if job ._remove .is_set ():
266+ self .logger .debug ('Removing job %s' , job .name )
267+ job .job_queue = None
268+ continue
269+
270+ if job .enabled :
292271 try :
293- t , job = self .queue .get (False )
294-
295- except Empty :
296- break
297-
298- self .logger .debug ('Peeked at %s with t=%f' , job .name , t )
299-
300- if t > now :
301- # We can get here in two conditions:
302- # 1. At the second or later pass of the while loop, after we've already
303- # processed the job(s) we were supposed to at this time.
304- # 2. At the first iteration of the loop only if `self.put()` had triggered
305- # `self.__tick` because `self._next_peek` wasn't set
306- self .logger .debug ("Next task isn't due yet. Finished!" )
307- self .queue .put ((t , job ))
308- self ._set_next_peek (t )
309- break
310-
311- if job ._remove .is_set ():
312- self .logger .debug ('Removing job %s' , job .name )
313- job .job_queue = None
314- continue
315-
316- if job .enabled :
317- try :
318- current_week_day = datetime .datetime .now ().weekday ()
319- if any (day == current_week_day for day in job .days ):
320- self .logger .debug ('Running job %s' , job .name )
321- job .run (self .bot )
322-
323- except :
324- self .logger .exception (
325- 'An uncaught error was raised while executing job %s' , job .name )
326-
327- else :
328- self .logger .debug ('Skipping disabled job %s' , job .name )
329-
330- if job .repeat :
331- self ._put (job , last_t = t )
332-
333- else :
334- self .logger .debug ('Dropping non-repeating job %s' , job .name )
335- job .job_queue = None
272+ current_week_day = datetime .datetime .now ().weekday ()
273+ if any (day == current_week_day for day in job .days ):
274+ self .logger .debug ('Running job %s' , job .name )
275+ job .run (self .bot )
276+
277+ except :
278+ self .logger .exception ('An uncaught error was raised while executing job %s' ,
279+ job .name )
280+
281+ else :
282+ self .logger .debug ('Skipping disabled job %s' , job .name )
283+
284+ if job .repeat :
285+ self ._put (job , last_t = t )
286+
287+ else :
288+ self .logger .debug ('Dropping non-repeating job %s' , job .name )
289+ job .job_queue = None
336290
337291 def start (self ):
338292 """
@@ -387,8 +341,7 @@ def stop(self):
387341
388342 def jobs (self ):
389343 """Returns a tuple of all jobs that are currently in the ``JobQueue``"""
390- with self .__queue_lock :
391- return tuple (job [1 ] for job in self .queue .queue if job )
344+ return tuple (job [1 ] for job in self .queue .queue if job )
392345
393346
394347class Job (object ):
@@ -446,7 +399,6 @@ def __init__(self,
446399 self ._remove = Event ()
447400 self ._enabled = Event ()
448401 self ._enabled .set ()
449- self ._immediate_run_in_progress = Event ()
450402
451403 def run (self , bot ):
452404 """Executes the callback function"""
@@ -459,99 +411,6 @@ def schedule_removal(self):
459411 """
460412 self ._remove .set ()
461413
462- def _wrap_callback (self , old_due_promise , keep_schedule , skip_next ):
463- """Wraps the callback function into two other functions and returns the result"""
464- original_callback = self .callback
465-
466- def rescheduled (bot , job ):
467- """The callback function for the rescheduled run"""
468- # Run the original callback function
469- original_callback (bot , job )
470-
471- # If job is non-repeating, restore the callback, ignore everything else and bail
472- if not self .repeat :
473- self .callback = original_callback
474- return
475-
476- # Adjust the interval so that the next run is scheduled like it was before
477- if keep_schedule :
478- original_interval = self .interval
479-
480- try :
481- old_due = old_due_promise .result (timeout = 1.0 )
482-
483- except TimeoutError :
484- # Possible race condition when the JobQueue wants to run this job before it
485- # could run the Promise in the main thread. The JobQueue thread waits for
486- # the Promise to resolve, but the main thread waits for the JobQueue to release
487- # the __queue_lock so it can reschedule this job.
488- # In case that happens, simply wrap the callback function again and pretend
489- # like nothing happened yet.
490- self .callback = original_callback
491- self .callback = self ._wrap_callback (old_due_promise , keep_schedule , skip_next )
492- return
493-
494- self .interval = old_due - time .time ()
495-
496- def next_callback (bot , job ):
497- """The callback function for the run that was originally next"""
498-
499- # Restore callback and interval
500- self .callback = original_callback
501-
502- if keep_schedule :
503- self .interval = original_interval
504-
505- if not skip_next :
506- original_callback (bot , job )
507-
508- self ._immediate_run_in_progress .clear ()
509-
510- self .callback = next_callback
511-
512- return rescheduled
513-
514- def run_immediately (self , keep_schedule = True , skip_next = True ):
515- """
516- Puts this job to the front of the job queue, scheduled to run immediately.
517-
518- Args:
519- keep_schedule (Optional[bool]): If set to ``True``, which is the default, the job will
520- be re-scheduled so that the original schedule (as defined by the starting time and
521- interval) is not changed. If set to ``False``, the schedule will reset so that the
522- next scheduled time is calculated from the current time and the interval.
523- This parameter is ignored if the job is not repeating.
524- skip_next (Optional[bool]): If set to ``True``, which is the default, the next
525- scheduled execution will be skipped, effectively re-scheduling it to now.
526- If set to ``False``, this execution is an additional, completely unscheduled
527- execution.
528- This parameter is ignored if the job is not repeating.
529-
530- Raises:
531- NotImplementedError: If you use this method a second time before the job either ran
532- the originally scheduled execution once, or has skipped it.
533- ValueError: If the job is disabled at the moment
534- """
535- if self ._immediate_run_in_progress .is_set ():
536- raise NotImplementedError ("You can't use 'run_immediately' again until the job has "
537- "returned to it's normal state. Sorry about that." )
538-
539- if not self .enabled :
540- raise ValueError ("Job is disabled" )
541-
542- self ._immediate_run_in_progress .set ()
543- # Wrap the old due time in a Promise
544- old_due_promise = Promise (
545- self .job_queue .update_job_due_time , # pylint: disable=no-member
546- [self , time .time ()],
547- {})
548-
549- # Wrap the callback in the wrapper function
550- self .callback = self ._wrap_callback (old_due_promise , keep_schedule , skip_next )
551-
552- # Run the promise to reschedule the job
553- old_due_promise .run ()
554-
555414 @property
556415 def enabled (self ):
557416 return self ._enabled .is_set ()
0 commit comments