|  | @@ -586,16 +586,36 @@ class PeriodicTask(Task):
 | 
	
		
			
				|  |  |          super(PeriodicTask, self).__init__()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      def remaining_estimate(self, last_run_at):
 | 
	
		
			
				|  |  | -        rem = (last_run_at + self.run_every) - datetime.now()
 | 
	
		
			
				|  |  | -        now = False
 | 
	
		
			
				|  |  | -        if rem.days == -1:
 | 
	
		
			
				|  |  | -            now = True
 | 
	
		
			
				|  |  | -            rem = self.run_every
 | 
	
		
			
				|  |  | -        return now, rem.seconds + (rem.microseconds / 10e5)
 | 
	
		
			
				|  |  | +        return (last_run_at + self.run_every) - datetime.now()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def timedelta_seconds(self, d):
 | 
	
		
			
				|  |  | +        if d.days < 0:
 | 
	
		
			
				|  |  | +            return 0
 | 
	
		
			
				|  |  | +        return d.days * 86400 + d.seconds + (d.microseconds / 10e5)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      def is_due(self, last_run_at):
 | 
	
		
			
				|  |  | -        """Returns ``True`` if the task is due.
 | 
	
		
			
				|  |  | +        """Returns tuple of two items ``(is_due, next_time_to_run)``,
 | 
	
		
			
				|  |  | +        where next time to run is in seconds.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        e.g.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        * ``(True, 20)``, means the task should be run now, and the next
 | 
	
		
			
				|  |  | +            time to run is in 20 seconds.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        * ``(False, 12)``, means the task should be run in 12 seconds.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        You can override this to decide the interval at runtime,
 | 
	
		
			
				|  |  | +        but keep in mind the value of ``CELERYBEAT_MAX_LOOP_INTERVAL``, which
 | 
	
		
			
				|  |  | +        decides the maximum number of seconds celerybeat can sleep between
 | 
	
		
			
				|  |  | +        re-checking the periodic task intervals. So if you dynamically change
 | 
	
		
			
				|  |  | +        the next run at value, and the max interval is set to 5 minutes, it
 | 
	
		
			
				|  |  | +        will take 5 minutes for the change to take effect, so you may
 | 
	
		
			
				|  |  | +        consider lowering the value of ``CELERYBEAT_MAX_LOOP_INTERVAL`` if
 | 
	
		
			
				|  |  | +        responsiveness if of importance to you.
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        You can override this to decide the interval at runtime.
 | 
	
		
			
				|  |  |          """
 | 
	
		
			
				|  |  | -        return self.remaining_estimate(last_run_at)
 | 
	
		
			
				|  |  | +        rem_delta = self.remaining_estimate(last_run_at)
 | 
	
		
			
				|  |  | +        rem = self.timedelta_seconds(rem_delta)
 | 
	
		
			
				|  |  | +        if rem == 0:
 | 
	
		
			
				|  |  | +            return True, self.timedelta_seconds(self.run_every)
 | 
	
		
			
				|  |  | +        return False, rem
 |