# Path: botoflow/core/async_traceback.py
# def print_exc(limit=None, file=None):
# def format_exc(limit=None, exception=None, tb_list=None):
# def extract_tb(limit=None):
# 
# Path: botoflow/workers/threaded_executor.py
# class ThreadedExecutor(object):
#     """This will execute a worker using multiple threads."""
# 
#     def __init__(self, worker):
#         self._worker = worker
# 
#     def start(self):
#         """Start the worker. This method does not block."""
#         log.debug("Starting worker %s", self)
# 
#         self._worker_shutdown = False  # when True will indicate shutdown
#         self._thread_queue = queue.Queue()  # to track the active threads
#         self._running = True
# 
#     def stop(self):
#         """Stops the worker threads.
#         To wait for all the threads to terminate, call:
# 
#         .. code-block:: python
# 
#             worker.start()
#             time.sleep(360)
#             worker.stop()
#             worker.join()  # will block
# 
#         """
#         log.debug("Stopping worker %s", self)
#         if not self.is_running:
#             return False
# 
#         self._worker_shutdown = True
# 
#     def join(self):
#         """Will wait till all the threads are terminated
#         """
#         self._thread_queue.join()
#         self._running = False
# 
#     @property
#     def initializer(self):
#         """If set, the initializer function will be called after the thread
#         is started with the worker object as the first argument.
#         """
#         try:
#             return self.__initializer
#         except AttributeError:
#             return lambda obj: None
# 
#     @initializer.setter
#     def initializer(self, func):
#         self.__initializer = func
# 
#     @property
#     def is_running(self):
#         """Returns True if the worker is running"""
#         if hasattr(self, '_running'):
#             return self._running
#         return False


import threading
import logging
from ..core import async_traceback
from .threaded_executor import ThreadedExecutor

        .. code-block:: python

            worker.start(pollers=2)
            time.sleep(360)
            worker.stop()
            worker.join()  # will block

        """
        if pollers < 1:
            raise ValueError("poller_threads count must be greater than 0")

        super(ThreadedWorkflowExecutor, self).start()

        start_condition = threading.Condition()

        # noinspection PyShadowingNames
        def run_decider(self):
            self._thread_queue.get()
            thread = threading.current_thread()
            log.debug("Poller/decider %s started", thread.name)
            initializer = self.initializer
            initializer(self)

            try:
                while not self._worker_shutdown:
                    with start_condition:
                        start_condition.notifyAll()
                    self._worker.run_once()
            except Exception as err:

# Path: botoflow/core/async_traceback.py
# def print_exc(limit=None, file=None):
# def format_exc(limit=None, exception=None, tb_list=None):
# def extract_tb(limit=None):
# 
# Path: botoflow/workers/threaded_executor.py
# class ThreadedExecutor(object):
#     """This will execute a worker using multiple threads."""
# 
#     def __init__(self, worker):
#         self._worker = worker
# 
#     def start(self):
#         """Start the worker. This method does not block."""
#         log.debug("Starting worker %s", self)
# 
#         self._worker_shutdown = False  # when True will indicate shutdown
#         self._thread_queue = queue.Queue()  # to track the active threads
#         self._running = True
# 
#     def stop(self):
#         """Stops the worker threads.
#         To wait for all the threads to terminate, call:
# 
#         .. code-block:: python
# 
#             worker.start()
#             time.sleep(360)
#             worker.stop()
#             worker.join()  # will block
# 
#         """
#         log.debug("Stopping worker %s", self)
#         if not self.is_running:
#             return False
# 
#         self._worker_shutdown = True
# 
#     def join(self):
#         """Will wait till all the threads are terminated
#         """
#         self._thread_queue.join()
#         self._running = False
# 
#     @property
#     def initializer(self):
#         """If set, the initializer function will be called after the thread
#         is started with the worker object as the first argument.
#         """
#         try:
#             return self.__initializer
#         except AttributeError:
#             return lambda obj: None
# 
#     @initializer.setter
#     def initializer(self, func):
#         self.__initializer = func
# 
#     @property
#     def is_running(self):
#         """Returns True if the worker is running"""
#         if hasattr(self, '_running'):
#             return self._running
#         return False


# Path: botoflow/workers/threaded_workflow_executor.py
import threading
import logging
from ..core import async_traceback
from .threaded_executor import ThreadedExecutor


        .. code-block:: python

            worker.start(pollers=2)
            time.sleep(360)
            worker.stop()
            worker.join()  # will block

        """
        if pollers < 1:
            raise ValueError("poller_threads count must be greater than 0")

        super(ThreadedWorkflowExecutor, self).start()

        start_condition = threading.Condition()

        # noinspection PyShadowingNames
        def run_decider(self):
            self._thread_queue.get()
            thread = threading.current_thread()
            log.debug("Poller/decider %s started", thread.name)
            initializer = self.initializer
            initializer(self)

            try:
                while not self._worker_shutdown:
                    with start_condition:
                        start_condition.notifyAll()
                    self._worker.run_once()
            except Exception as err:

                tb_list = async_traceback.extract_tb()