|  | @@ -1,5 +1,7 @@
 | 
	
		
			
				|  |  | +import time
 | 
	
		
			
				|  |  | +from collections import deque
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  from celery.task.base import Task
 | 
	
		
			
				|  |  | -from celery.task.builtins import PingTask
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  class CoroutineTask(Task):
 | 
	
	
		
			
				|  | @@ -29,25 +31,37 @@ class Aggregate(CoroutineTask):
 | 
	
		
			
				|  |  |      abstract = True
 | 
	
		
			
				|  |  |      proxied = None
 | 
	
		
			
				|  |  |      minlen = 100
 | 
	
		
			
				|  |  | +    time_max = 60
 | 
	
		
			
				|  |  | +    _time_since = None
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      def body(self):
 | 
	
		
			
				|  |  | -        waiting = []
 | 
	
		
			
				|  |  | +        waiting = deque()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        timesince = time.time()
 | 
	
		
			
				|  |  |          while True:
 | 
	
		
			
				|  |  |              argtuple = (yield)
 | 
	
		
			
				|  |  |              waiting.append(argtuple)
 | 
	
		
			
				|  |  | -            if len(waiting) >= self.minlen:
 | 
	
		
			
				|  |  | -                res = []
 | 
	
		
			
				|  |  | -                for task_args, task_kwargs in waiting:
 | 
	
		
			
				|  |  | -                    try:
 | 
	
		
			
				|  |  | -                        res.append(self.proxied(*args, **kwargs))
 | 
	
		
			
				|  |  | -                    except Exception, exc:
 | 
	
		
			
				|  |  | -                        pass # TODO handle errors here, please
 | 
	
		
			
				|  |  | -                yield res
 | 
	
		
			
				|  |  | +            if self._expired() or len(waiting) >= self.minlen:
 | 
	
		
			
				|  |  | +                yield self.process(waiting)
 | 
	
		
			
				|  |  | +                waiting.clear()
 | 
	
		
			
				|  |  |              else:
 | 
	
		
			
				|  |  |                  yield None
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    def process(self, jobs):
 | 
	
		
			
				|  |  | +        """Jobs is a deque with the arguments gathered so far.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        Arguments is a args, kwargs tuple.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        """
 | 
	
		
			
				|  |  | +        raise NotImplementedError(
 | 
	
		
			
				|  |  | +                "Subclasses of Aggregate needs to implement process()")
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def _expired(self):
 | 
	
		
			
				|  |  | +        if not self._time_since:
 | 
	
		
			
				|  |  | +            self._time_since = time.time()
 | 
	
		
			
				|  |  | +            return False
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class AggregatePing(Aggregate):
 | 
	
		
			
				|  |  | -    proxied = PingTask
 | 
	
		
			
				|  |  | -    n = 100
 | 
	
		
			
				|  |  | +        if time.time() + self.time_max > self._time_since:
 | 
	
		
			
				|  |  | +            self._time_since = time.time()
 | 
	
		
			
				|  |  | +            return True
 | 
	
		
			
				|  |  | +        return False
 |