|
@@ -0,0 +1,120 @@
|
|
|
+
|
|
|
+import threading
|
|
|
+
|
|
|
+from eventlet import GreenPile, GreenPool
|
|
|
+from eventlet import hubs
|
|
|
+from eventlet import spawn_n
|
|
|
+from eventlet.greenthread import sleep
|
|
|
+from Queue import Empty, Queue as LightQueue
|
|
|
+
|
|
|
+from celery import log
|
|
|
+from celery.utils.functional import partial
|
|
|
+from celery.datastructures import ExceptionInfo
|
|
|
+
|
|
|
+RUN = 0x1
|
|
|
+CLOSE = 0x2
|
|
|
+TERMINATE = 0x3
|
|
|
+
|
|
|
+
|
|
|
+accept_lock = threading.Lock()
|
|
|
+
|
|
|
+
|
|
|
+def do_work(target, args=(), kwargs={}, callback=None,
|
|
|
+ accept_callback=None, method_queue=None):
|
|
|
+ method_queue.delegate(accept_callback)
|
|
|
+ callback(target(*args, **kwargs))
|
|
|
+
|
|
|
+
|
|
|
+class Waiter(threading.Thread):
|
|
|
+
|
|
|
+ def __init__(self, inqueue, limit):
|
|
|
+ self.inqueue = inqueue
|
|
|
+ self.limit = limit
|
|
|
+ self._state = None
|
|
|
+ threading.Thread.__init__(self)
|
|
|
+
|
|
|
+ def run(self):
|
|
|
+ hubs.use_hub()
|
|
|
+ pool = GreenPool(self.limit)
|
|
|
+ pile = GreenPile(pool)
|
|
|
+ self._state = RUN
|
|
|
+ inqueue = self.inqueue
|
|
|
+
|
|
|
+ def get_from_queue_forever():
|
|
|
+ while self._state == RUN:
|
|
|
+ try:
|
|
|
+ print("+INQUEUE GET")
|
|
|
+ m = inqueue.get_nowait()
|
|
|
+ print("-INQUEUE GET")
|
|
|
+ except Empty:
|
|
|
+ sleep(0.3)
|
|
|
+ else:
|
|
|
+ print("+SPAWN")
|
|
|
+ pile.spawn(*m)
|
|
|
+ print("-SPAWN")
|
|
|
+
|
|
|
+ def wait_for_pile_forever():
|
|
|
+ while self._state == RUN:
|
|
|
+ print("+CALLING PILE NEXT")
|
|
|
+ pile.next()
|
|
|
+ print("-CALLING PILE NEXT")
|
|
|
+
|
|
|
+ spawn_n(get_from_queue_forever)
|
|
|
+ spawn_n(wait_for_pile_forever)
|
|
|
+
|
|
|
+ while self._state == RUN:
|
|
|
+ sleep(0.1)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+class TaskPool(object):
|
|
|
+ _state = None
|
|
|
+
|
|
|
+ def __init__(self, limit, logger=None, **kwargs):
|
|
|
+ self.limit = limit
|
|
|
+ self.logger = logger or log.get_default_logger()
|
|
|
+ self._pool = None
|
|
|
+
|
|
|
+ def start(self):
|
|
|
+ self._state = RUN
|
|
|
+ self._out = LightQueue()
|
|
|
+ self._waiter = Waiter(self._out, self.limit)
|
|
|
+ self._waiter.start()
|
|
|
+
|
|
|
+ def stop(self):
|
|
|
+ self._state = CLOSE
|
|
|
+ self._pool.pool.waitall()
|
|
|
+ self._waiter._state = TERMINATE
|
|
|
+ self._state = TERMINATE
|
|
|
+
|
|
|
+ def apply_async(self, target, args=None, kwargs=None, callbacks=None,
|
|
|
+ errbacks=None, accept_callback=None, **compat):
|
|
|
+ if self._state != RUN:
|
|
|
+ return
|
|
|
+ args = args or []
|
|
|
+ kwargs = kwargs or {}
|
|
|
+ callbacks = callbacks or []
|
|
|
+ errbacks = errbacks or []
|
|
|
+
|
|
|
+ on_ready = partial(self.on_ready, callbacks, errbacks)
|
|
|
+
|
|
|
+ self.logger.debug("GreenPile: Spawn %s (args:%s kwargs:%s)" % (
|
|
|
+ target, args, kwargs))
|
|
|
+
|
|
|
+ print("+OUTQUEUE.PUT")
|
|
|
+ self._out.put((do_work, target, args, kwargs,
|
|
|
+ on_ready, accept_callback, self.method_queue))
|
|
|
+ print("-OUTQUEUE.PUT")
|
|
|
+
|
|
|
+
|
|
|
+ def on_ready(self, callbacks, errbacks, ret_value):
|
|
|
+ """What to do when a worker task is ready and its return value has
|
|
|
+ been collected."""
|
|
|
+
|
|
|
+ if isinstance(ret_value, ExceptionInfo):
|
|
|
+ if isinstance(ret_value.exception, (
|
|
|
+ SystemExit, KeyboardInterrupt)): # pragma: no cover
|
|
|
+ raise ret_value.exception
|
|
|
+ [errback(ret_value) for errback in errbacks]
|
|
|
+ else:
|
|
|
+ [callback(ret_value) for callback in callbacks]
|