--- /dev/null
+import threading
+import traceback
+import time
+from Queue import Queue
+from sfa.util.sfalogging import logger
+
+def ThreadedMethod(callable, results, errors):
+ """
+ A function decorator that returns a running thread. The thread
+ runs the specified callable and stores the result in the specified
+ results queue
+ """
+ def wrapper(args, kwds):
+ class ThreadInstance(threading.Thread):
+ def run(self):
+ try:
+ results.put(callable(*args, **kwds))
+ except Exception, e:
+ logger.log_exc('ThreadManager: Error in thread: ')
+ errors.put(traceback.format_exc())
+
+ thread = ThreadInstance()
+ thread.start()
+ return thread
+ return wrapper
+
+
+
+class ThreadManager:
+ """
+ ThreadManager executes a callable in a thread and stores the result
+ in a thread safe queue.
+ """
+
+ def __init__(self):
+ self.results = Queue()
+ self.errors = Queue()
+ self.threads = []
+
+ def run (self, method, *args, **kwds):
+ """
+ Execute a callable in a separate thread.
+ """
+ method = ThreadedMethod(method, self.results, self.errors)
+ thread = method(args, kwds)
+ self.threads.append(thread)
+
+ start = run
+
+ def join(self):
+ """
+ Wait for all threads to complete
+ """
+ for thread in self.threads:
+ thread.join()
+
+ def get_results(self, lenient=True):
+ """
+ Return a list of all the results so far. Blocks until
+ all threads are finished.
+ If lienent is set to false the error queue will be checked before
+ the response is returned. If there are errors in the queue an SFA Fault will
+ be raised.
+ """
+ self.join()
+ results = []
+ if not lenient:
+ errors = self.get_errors()
+ if errors:
+ raise Exception(errors[0])
+
+ while not self.results.empty():
+ results.append(self.results.get())
+ return results
+
+ def get_errors(self):
+ """
+ Return a list of all errors. Blocks untill all threads are finished
+ """
+ self.join()
+ errors = []
+ while not self.errors.empty():
+ errors.append(self.errors.get())
+ return errors
+
+ def get_return_value(self):
+ """
+ Get the value that should be returuned to the client. If there are errors then the
+ first error is returned. If there are no errors, then the first result is returned
+ """
+
+
+if __name__ == '__main__':
+
+ def f(name, n, sleep=1):
+ nums = []
+ for i in range(n, n+5):
+ print "%s: %s" % (name, i)
+ nums.append(i)
+ time.sleep(sleep)
+ return nums
+ def e(name, n, sleep=1):
+ nums = []
+ for i in range(n, n+3) + ['n', 'b']:
+ print "%s: 1 + %s:" % (name, i)
+ nums.append(i + 1)
+ time.sleep(sleep)
+ return nums
+
+ threads = ThreadManager()
+ threads.run(f, "Thread1", 10, 2)
+ threads.run(f, "Thread2", -10, 1)
+ threads.run(e, "Thread3", 19, 1)
+
+ #results = threads.get_results()
+ #errors = threads.get_errors()
+ #print "Results:", results
+ #print "Errors:", errors
+ results_xlenient = threads.get_results(lenient=False)
+