|  | @@ -12,6 +12,7 @@
 | 
	
		
			
				|  |  |  from __future__ import absolute_import
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import errno
 | 
	
		
			
				|  |  | +import gc
 | 
	
		
			
				|  |  |  import os
 | 
	
		
			
				|  |  |  import select
 | 
	
		
			
				|  |  |  import socket
 | 
	
	
		
			
				|  | @@ -20,7 +21,7 @@ import struct
 | 
	
		
			
				|  |  |  from collections import deque, namedtuple
 | 
	
		
			
				|  |  |  from pickle import HIGHEST_PROTOCOL
 | 
	
		
			
				|  |  |  from time import sleep, time
 | 
	
		
			
				|  |  | -from weakref import ref
 | 
	
		
			
				|  |  | +from weakref import WeakValueDictionary, ref
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  from amqp.utils import promise
 | 
	
		
			
				|  |  |  from billiard import forking_enable
 | 
	
	
		
			
				|  | @@ -519,32 +520,56 @@ class TaskPool(BasePool):
 | 
	
		
			
				|  |  |              'all': ', '.join(per(v, total) for v in vals)
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    def _on_soft_timeout(self, job, soft, hard, hub, now=time):
 | 
	
		
			
				|  |  | +        if hard:
 | 
	
		
			
				|  |  | +            self._tref_for_id[job] = hub.timer.apply_at(
 | 
	
		
			
				|  |  | +                now() + (hard - soft),
 | 
	
		
			
				|  |  | +                self._on_hard_timeout, (job, soft, hard, hub))
 | 
	
		
			
				|  |  | +        try:
 | 
	
		
			
				|  |  | +            result = self._pool.cache[job]
 | 
	
		
			
				|  |  | +        except KeyError:
 | 
	
		
			
				|  |  | +            pass  # job ready
 | 
	
		
			
				|  |  | +        else:
 | 
	
		
			
				|  |  | +            self.on_soft_timeout(result)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def _on_hard_timeout(self, job):
 | 
	
		
			
				|  |  | +        try:
 | 
	
		
			
				|  |  | +            result = self._pool.cache[job]
 | 
	
		
			
				|  |  | +        except KeyError:
 | 
	
		
			
				|  |  | +            pass  # job ready
 | 
	
		
			
				|  |  | +        else:
 | 
	
		
			
				|  |  | +            self.on_hard_timeout(result)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      def _create_timelimit_handlers(self, hub, now=time):
 | 
	
		
			
				|  |  |          apply_after = hub.timer.apply_after
 | 
	
		
			
				|  |  | -        apply_at = hub.timer.apply_at
 | 
	
		
			
				|  |  |          on_soft_timeout = self.on_soft_timeout
 | 
	
		
			
				|  |  |          on_hard_timeout = self.on_hard_timeout
 | 
	
		
			
				|  |  | +        trefs = self._tref_for_id = WeakValueDictionary()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        def on_timeout_set(R, soft, hard):
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            def _on_soft_timeout():
 | 
	
		
			
				|  |  | -                if hard:
 | 
	
		
			
				|  |  | -                    R._tref = apply_at(now() + (hard - soft),
 | 
	
		
			
				|  |  | -                                       on_hard_timeout, (R, ))
 | 
	
		
			
				|  |  | -                on_soft_timeout(R)
 | 
	
		
			
				|  |  | +        def on_timeout_set(job, soft, hard):
 | 
	
		
			
				|  |  |              if soft:
 | 
	
		
			
				|  |  | -                R._tref = apply_after(soft * 1000.0, _on_soft_timeout)
 | 
	
		
			
				|  |  | +                trefs[job] = apply_after(
 | 
	
		
			
				|  |  | +                    soft * 1000.0,
 | 
	
		
			
				|  |  | +                    self._on_soft_timeout, (job, soft, hard, hub),
 | 
	
		
			
				|  |  | +                )
 | 
	
		
			
				|  |  |              elif hard:
 | 
	
		
			
				|  |  | -                R._tref = apply_after(hard * 1000.0,
 | 
	
		
			
				|  |  | -                                      on_hard_timeout, (R, ))
 | 
	
		
			
				|  |  | +                trefs[job] = apply_after(
 | 
	
		
			
				|  |  | +                    hard * 1000.0,
 | 
	
		
			
				|  |  | +                    self._on_hard_timeout, (job, )
 | 
	
		
			
				|  |  | +                )
 | 
	
		
			
				|  |  |          self._pool.on_timeout_set = on_timeout_set
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        def on_timeout_cancel(result):
 | 
	
		
			
				|  |  | +        def on_timeout_cancel(job):
 | 
	
		
			
				|  |  |              try:
 | 
	
		
			
				|  |  | -                result._tref.cancel()
 | 
	
		
			
				|  |  | -                delattr(result, '_tref')
 | 
	
		
			
				|  |  | -            except AttributeError:
 | 
	
		
			
				|  |  | -                pass
 | 
	
		
			
				|  |  | +                tref = trefs.pop(job)
 | 
	
		
			
				|  |  | +                tref.cancel()
 | 
	
		
			
				|  |  | +                del(tref)
 | 
	
		
			
				|  |  | +                # Will not be reclaimed quickly enough on some platforms,
 | 
	
		
			
				|  |  | +                # so the memory is growing and still not released back to the
 | 
	
		
			
				|  |  | +                # OS.
 | 
	
		
			
				|  |  | +                gc.collect()
 | 
	
		
			
				|  |  | +            except (KeyError, AttributeError):
 | 
	
		
			
				|  |  | +                pass  # out of scope
 | 
	
		
			
				|  |  |          self._pool.on_timeout_cancel = on_timeout_cancel
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      def _create_process_handlers(self, hub, READ=READ, ERR=ERR):
 |