class BlockingExecutor(impl_pooledexecutor.PooledExecutor):
    """A message executor which blocks the current thread.

    The blocking executor's start() method functions as a request processing
    loop - i.e. it blocks, processes messages and only returns when stop() is
    called from a dispatched method.

    Method calls are dispatched in the current thread, so only a single method
    call can be executing at once. This executor is likely to only be useful
    for simple demo programs.
    """

    _executor_cls = lambda __, ___: futurist.SynchronousExecutor()
    _thread_cls = FakeBlockingThread

    def __init__(self, *args, **kwargs):
        super(BlockingExecutor, self).__init__(*args, **kwargs)

    def execute(self):
        '''Explicitly run the executor in the current context.'''
        # NOTE(mdbooth): Splitting start into start and execute for the
        # blocking executor closes a potential race. On a non-blocking
        # executor, calling start performs some initialisation synchronously
        # before starting the executor and returning control to the caller. In
        # the non-blocking caller there was no externally visible boundary
        # between the completion of initialisation and the start of execution,
        # meaning the caller cannot indicate to another thread that
        # initialisation is complete. With the split, the start call for the
        # blocking executor becomes analogous to the non-blocking case,
        # indicating that initialisation is complete. The caller can then
        # synchronously call execute.
        if self._poller is not None:
            self._poller.execute()
Exemplo n.º 2
0
    def setUp(self):
        super(TestDecisionEngineThreadPool, self).setUp()

        self.m_function = mock.Mock()
        self.m_function.return_value = None
        self.m_do_while_function = mock.Mock()
        self.m_do_while_function.return_value = None

        # override the underlying threadpool for testing
        # this is like a 'fixture' were the original state of the singleton
        # is restored after these tests finish but the threadpool can still
        # be used as intended with its methods
        self.p_threadool = mock.patch.object(
            threading,
            'DecisionEngineThreadPool',
            new=threading.DecisionEngineThreadPool)
        self.m_threadpool = self.p_threadool.start()
        self.addCleanup(self.p_threadool.stop)

        # bind unbound patched methods for python 2.7 compatibility
        # class methods can be used unbounded in Python 3.x
        self.m_threadpool.submit = self.m_threadpool.submit.__get__(
            self.m_threadpool, threading.DecisionEngineThreadPool)

        # perform all tests synchronously
        self.m_threadpool._threadpool = futurist.SynchronousExecutor()
Exemplo n.º 3
0
class ProxyExecutor(object):
    KIND_TO_FACTORY = {
        'threaded': (lambda:
                     futurist.ThreadPoolExecutor(max_workers=1)),
        'synchronous': lambda: futurist.SynchronousExecutor(),
    }

    # Provide a few common aliases...
    KIND_TO_FACTORY['thread'] = KIND_TO_FACTORY['threaded']
    KIND_TO_FACTORY['threading'] = KIND_TO_FACTORY['threaded']
    KIND_TO_FACTORY['sync'] = KIND_TO_FACTORY['synchronous']

    DEFAULT_KIND = 'threaded'

    def __init__(self, driver_name, default_executor_factory):
        self.default_executor_factory = default_executor_factory
        self.driver_name = driver_name
        self.started = False
        self.executor = None
        self.internally_owned = True

    @classmethod
    def build(cls, driver_name, options):
        default_executor_fact = cls.KIND_TO_FACTORY[cls.DEFAULT_KIND]
        if 'executor' in options:
            executor_kind = options['executor']
            try:
                default_executor_fact = cls.KIND_TO_FACTORY[executor_kind]
            except KeyError:
                executors_known = sorted(list(cls.KIND_TO_FACTORY))
                raise tooz.ToozError("Unknown executor"
                                     " '%s' provided, accepted values"
                                     " are %s" % (executor_kind,
                                                  executors_known))
        return cls(driver_name, default_executor_fact)

    def start(self):
        if self.started:
            return
        self.executor = self.default_executor_factory()
        self.started = True

    def stop(self):
        executor = self.executor
        self.executor = None
        if executor is not None:
            executor.shutdown()
        self.started = False

    def submit(self, cb, *args, **kwargs):
        if not self.started:
            raise tooz.ToozError("%s driver asynchronous executor"
                                 " has not been started"
                                 % self.driver_name)
        try:
            return self.executor.submit(cb, *args, **kwargs)
        except RuntimeError:
            raise tooz.ToozError("%s driver asynchronous executor has"
                                 " been shutdown" % self.driver_name)
Exemplo n.º 4
0
class BlockingExecutor(impl_pooledexecutor.PooledExecutor):
    """A message executor which blocks the current thread.

    The blocking executor's start() method functions as a request processing
    loop - i.e. it blocks, processes messages and only returns when stop() is
    called from a dispatched method.

    Method calls are dispatched in the current thread, so only a single method
    call can be executing at once. This executor is likely to only be useful
    for simple demo programs.
    """

    _executor_cls = lambda __, ___: futurist.SynchronousExecutor()
    _thread_cls = FakeBlockingThread
Exemplo n.º 5
0
 def setUp(self):
     super(BaseTest, self).setUp()
     if not self.IS_FUNCTIONAL:
         self.init_test_conf()
     self.session = db.get_writer_session()
     engine = self.session.get_bind()
     db.Base.metadata.create_all(engine)
     engine.connect()
     self.addCleanup(engine.dispose)
     plugins_base._HOOKS_MGR = None
     node_cache._SEMAPHORES = lockutils.Semaphores()
     patch = mock.patch.object(i18n, '_', lambda s: s)
     patch.start()
     # 'p=patch' magic is due to how closures work
     self.addCleanup(lambda p=patch: p.stop())
     utils._EXECUTOR = futurist.SynchronousExecutor(green=True)
Exemplo n.º 6
0
 def test_sync_executor_creation(self):
     with futurist.SynchronousExecutor() as e:
         eng = self._create_engine(executor=e)
         self.assertIsInstance(eng._task_executor,
                               executor.ParallelThreadTaskExecutor)
Exemplo n.º 7
0
 def runner(bot, slack_client, slack_sender):
     try:
         self_id = slack_client.server.login_data['self']['id']
     except (TypeError, KeyError):
         self_id = None
     if not self_id:
         return
     attachments = [
         {
             'pretext': ("Initiating %s that runs with"
                         " cron schedule `%s`." % (what, period)),
             'mrkdwn_in': ['pretext'],
         },
     ]
     # This sends an initial 'kick' message that the rest of the
     # work will be rooted from (ie a subthread of).
     resp = slack_sender.post_send(attachments=attachments,
                                   channel=channel,
                                   as_user=True,
                                   link_names=True,
                                   text="Good %s." %
                                   bot.date_wrangler.get_when())
     m_headers = {
         m.VALIDATED_HEADER: True,
         m.TO_ME_HEADER: True,
         m.CHECK_AUTH_HEADER: False,
         m.ARGS_HEADER: args.copy(),
         m.DIRECT_CLS_HEADER: target_cls,
         m.IS_INTERNAL_HEADER: True,
     }
     m_channel_id = resp["channel"]
     m_body = munch.Munch({
         'channel':
         m_channel_id,
         'channel_name':
         channel,
         'channel_kind':
         su.ChannelKind.convert(m_channel_id),
         'ts':
         resp['ts'],
         'thread_ts':
         None,
         'directed':
         False,
         'targets': [
             self_id,
         ],
         'user_id':
         self_id,
         'user_name':
         '',
         # NOTE: not used since args header passed in which turns the
         # match that is made into a explicit match (which then means
         # the text is not matched).
         'text':
         '',
         'text_no_links':
         '',
     })
     message = slack_watcher.SlackMessage("slack/message", m_headers,
                                          m_body, slack_sender)
     su.insert_quick_link(message,
                          slack_base_url=bot.config.slack.get('base_url'))
     fut = bot.submit_message(
         message,
         c.TARGETED,
         # Avoid using the bot executors so that we don't cause
         # cycles (a user can trigger a periodic to manually run
         # and doing that will cause a thread to wait; so it can
         # be possible to deplete both pools if this is abused).
         executor=futurist.SynchronousExecutor())
     fut.add_done_callback(
         finishers.notify_slack_on_fail(bot, message, log=log))
     fut.result()
Exemplo n.º 8
0
    def __init__(self,
                 callables,
                 log=None,
                 executor_factory=None,
                 cond_cls=threading.Condition,
                 event_cls=threading.Event,
                 schedule_strategy='last_started',
                 now_func=utils.now,
                 on_failure=None):
        """Creates a new worker using the given periodic callables.

        :param callables: a iterable of tuple objects previously decorated
                          with the :py:func:`.periodic` decorator, each item
                          in the iterable is expected to be in the format
                          of ``(cb, args, kwargs)`` where ``cb`` is the
                          decorated function and ``args`` and ``kwargs`` are
                          any positional and keyword arguments to send into
                          the callback when it is activated (both ``args``
                          and ``kwargs`` may be provided as none to avoid
                          using them)
        :type callables: iterable
        :param log: logger to use when creating a new worker (defaults
                    to the module logger if none provided), it is currently
                    only used to report callback failures (if they occur)
        :type log: logger
        :param executor_factory: factory callable that can be used to generate
                                 executor objects that will be used to
                                 run the periodic callables (if none is
                                 provided one will be created that uses
                                 the :py:class:`~futurist.SynchronousExecutor`
                                 class)
        :type executor_factory: ExecutorFactory or any callable
        :param cond_cls: callable object that can
                          produce ``threading.Condition``
                          (or compatible/equivalent) objects
        :type cond_cls: callable
        :param event_cls: callable object that can produce ``threading.Event``
                          (or compatible/equivalent) objects
        :type event_cls: callable
        :param schedule_strategy: string to select one of the built-in
                                  strategies that can return the
                                  next time a callable should run
        :type schedule_strategy: string
        :param now_func: callable that can return the current time offset
                         from some point (used in calculating elapsed times
                         and next times to run); preferably this is
                         monotonically increasing
        :type now_func: callable
        :param on_failure: callable that will be called whenever a periodic
                           function fails with an error, it will be provided
                           four positional arguments and one keyword
                           argument, the first positional argument being the
                           callable that failed, the second being the type
                           of activity under which it failed (``IMMEDIATE`` or
                           ``PERIODIC``), the third being the spacing that the
                           callable runs at and the fourth ``exc_info`` tuple
                           of the failure. The keyword argument ``traceback``
                           will also be provided that may be be a string
                           that caused the failure (this is required for
                           executors which run out of process, as those can not
                           *currently* transfer stack frames across process
                           boundaries); if no callable is provided then a
                           default failure logging function will be used
                           instead (do note that
                           any user provided callable should not raise
                           exceptions on being called)
        :type on_failure: callable
        """
        if on_failure is not None and not six.callable(on_failure):
            raise ValueError("On failure callback %r must be"
                             " callable" % on_failure)
        self._tombstone = event_cls()
        self._waiter = cond_cls()
        self._dead = event_cls()
        self._active = event_cls()
        self._cond_cls = cond_cls
        self._watchers = []
        self._works = []
        for (cb, args, kwargs) in callables:
            if not six.callable(cb):
                raise ValueError("Periodic callback %r must be callable" % cb)
            missing_attrs = _check_attrs(cb)
            if missing_attrs:
                raise ValueError("Periodic callback %r missing required"
                                 " attributes %s" % (cb, missing_attrs))
            if cb._is_periodic:
                # Ensure these aren't none and if so replace them with
                # something more appropriate...
                if args is None:
                    args = self._NO_OP_ARGS
                if kwargs is None:
                    kwargs = self._NO_OP_KWARGS.copy()
                cb_metrics = self._INITIAL_METRICS.copy()
                work = Work(utils.get_callback_name(cb), cb, args, kwargs)
                watcher = Watcher(cb_metrics, work)
                self._works.append(work)
                self._watchers.append((cb_metrics, watcher))
        try:
            strategy = self.BUILT_IN_STRATEGIES[schedule_strategy]
            self._schedule_strategy = strategy[0]
            self._initial_schedule_strategy = strategy[1]
        except KeyError:
            valid_strategies = sorted(self.BUILT_IN_STRATEGIES.keys())
            raise ValueError("Scheduling strategy '%s' must be one of"
                             " %s selectable strategies" %
                             (schedule_strategy, valid_strategies))
        self._immediates, self._schedule = _build(
            now_func, self._works, self._initial_schedule_strategy)
        self._log = log or LOG
        if executor_factory is None:
            executor_factory = lambda: futurist.SynchronousExecutor()
        if on_failure is None:
            on_failure = functools.partial(_on_failure_log, self._log)
        self._on_failure = on_failure
        self._executor_factory = executor_factory
        self._now_func = now_func
Exemplo n.º 9
0
 def __init__(self):
     self._executor = futurist.SynchronousExecutor()
Exemplo n.º 10
0
 def _executor_factory():
     return futurist.SynchronousExecutor()
Exemplo n.º 11
0
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# NOTE: enable printing timestamp for additional data

import datetime

import eventlet
import futurist


def delayed_func():
    print("started")
    eventlet.sleep(3)
    print("done")


print(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
e = futurist.SynchronousExecutor()
print("before submit")
fut = e.submit(delayed_func)
eventlet.sleep(1)
print("Hello")
eventlet.sleep(1)
e.shutdown()
print(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))