示例#1
0
    def test_add_pull_and_push_queue_tasks(self):
        """Ensure that push and pull tasks can be added with add_tasks()."""

        from furious.async import Async
        from furious.batcher import Message
        from furious.test_stubs.appengine.queues import add_tasks
        from furious.test_stubs.appengine.queues import get_tasks
        from furious.test_stubs.appengine.queues import purge_tasks

        # Add tasks the normal way so we can get them and test readding them
        async = Async(target='time.ctime')
        async.start()
        async2 = Async(target='time.ctime')
        async2.start()
        Message(queue='default-pull').insert()

        task_dict = get_tasks(self.queue_service)

        # purge current tasks so we can verify how many we will add next.
        purge_tasks(self.queue_service)

        num_added = add_tasks(self.queue_service, task_dict)

        # Purge tasks to check how many tasks are in the queues
        num_queued = purge_tasks(self.queue_service)

        self.assertEqual(3, num_added)
        self.assertEqual(3, num_queued)
示例#2
0
    def test_purge_tasks_with_queue_names_provided(self, ctime):
        """When a list of queue_names is provided, ensure purge_tasks() clears
        the tasks and none are left to execute.
        Ensure the number of tasks cleared is correct.
        """

        from furious.async import Async
        from furious.batcher import Message
        from furious.test_stubs.appengine.queues import run as run_queues
        from furious.test_stubs.appengine.queues import purge_tasks

        # Enqueue a couple of tasks
        async = Async(target='time.ctime')
        async.start()
        async2 = Async(target='time.ctime')
        async2.start()

        Message(queue='default-pull').insert()

        num_cleared = purge_tasks(self.taskqueue_service, ['default'])

        # Run the tasks to check if tasks remain
        run_queues(self.taskqueue_service)

        # Ensure two tasks from the default queue were cleared.
        self.assertEqual(2, num_cleared)

        # Ensure no tasks were run
        self.assertEqual(0, ctime.call_count)
示例#3
0
    def test_purge_tasks_with_string_passed_to_queue_names(self, ctime):
        """If a single queue_name is passed to purge_tasks() instead of a list,
        ensure that the queue specified is still cleared.
        Ensure the number of tasks cleared is correct.
        """
        from furious.async import Async
        from furious.batcher import Message
        from furious.test_stubs.appengine.queues import run as run_queues
        from furious.test_stubs.appengine.queues import purge_tasks

        # Enqueue a couple of tasks
        async = Async(target='time.ctime')
        async.start()
        async2 = Async(target='time.ctime')
        async2.start()

        # Insert a pull task
        Message(queue='default-pull').insert()

        num_cleared = purge_tasks(self.taskqueue_service, 'default')

        # Run the tasks to check if tasks remain
        run_queues(self.taskqueue_service)

        # Ensure two tasks from the default queue were cleared.
        self.assertEqual(2, num_cleared)

        # Ensure no tasks were run
        self.assertEqual(0, ctime.call_count)
示例#4
0
    def test_start_hits_transient_error_retry_disabled(self, queue_mock,
                                                       sleep_mock):
        """Ensure if transient error retries are disabled, that those errors are
        re-raised immediately without any attempt to re-insert.
        """
        from google.appengine.api.taskqueue import TransientError
        from furious. async import Async

        queue_mock.return_value.add.side_effect = TransientError()

        async_job = Async("something",
                          queue='my_queue',
                          retry_transient_errors=False)

        self.assertRaises(TransientError, async_job.start)
        self.assertEqual(1, queue_mock.return_value.add.call_count)

        # Try again with the option enabled, this should cause a retry after a
        # delay, which we have also specified.
        queue_mock.reset_mock()
        async_job = Async("something",
                          queue='my_queue',
                          retry_transient_errors=True,
                          retry_delay=12)

        self.assertRaises(TransientError, async_job.start)
        self.assertEqual(2, queue_mock.return_value.add.call_count)
        sleep_mock.assert_called_once_with(12)
示例#5
0
    def test_purge_tasks_with_tasks(self, ctime):
        """After queues are run, ensure no tasks are left to execute.
        Ensure the number of tasks cleared is correct.
        """

        from furious.async import Async
        from furious.batcher import Message
        from furious.test_stubs.appengine.queues import run as run_queues
        from furious.test_stubs.appengine.queues import purge_tasks

        # Enqueue a couple of tasks
        async = Async(target='time.ctime')
        async.start()
        async2 = Async(target='time.ctime')
        async2.start()

        Message(queue='default-pull').insert()

        num_cleared = purge_tasks(self.taskqueue_service)

        # Run the tasks to check if tasks remain
        run_queues(self.taskqueue_service)

        # Ensure three tasks were cleared, from 'default' and 'default-pull'.
        self.assertEqual(3, num_cleared)

        # Ensure no tasks were run
        self.assertEqual(0, ctime.call_count)
示例#6
0
    def test_to_dict_with_callbacks(self):
        """Ensure to_dict correctly encodes callbacks."""
        from furious. async import Async

        options = {
            'callbacks': {
                'success': self.__class__.test_to_dict_with_callbacks,
                'failure': "failure_function",
                'exec': Async(target=dir)
            }
        }

        job = Async('nonexistant', **options.copy())

        options['job'] = ('nonexistant', None, None)
        options['callbacks'] = {
            'success': ("furious.tests.test_async."
                        "TestAsync.test_to_dict_with_callbacks"),
            'failure':
            "failure_function",
            'exec': {
                'job': ('dir', None, None),
                '_recursion': {
                    'current': 0,
                    'max': 100
                },
                '_type': 'furious.async.Async'
            }
        }
        options['_recursion'] = {'current': 0, 'max': 100}
        options['_type'] = 'furious.async.Async'

        self.assertEqual(options, job.to_dict())
示例#7
0
    def test_double_init_raises_error(self):
        """Ensure initing twice raises a ContextExistsError."""
        from furious. async import Async
        from furious.context._execution import execution_context_from_async
        from furious.errors import ContextExistsError

        execution_context_from_async(Async(target=dir))
        self.assertRaises(ContextExistsError, execution_context_from_async,
                          Async(target=dir))
    def test_Abort(self, dir_mock, mock_start):
        """Ensures that when Abort is raised, the Async immediately stops."""
        import logging

        from furious.async import Async
        from furious.context._execution import _ExecutionContext
        from furious.errors import Abort
        from furious.processors import run_job

        class AbortLogHandler(logging.Handler):

            def emit(self, record):
                if record.levelno >= logging.ERROR:
                    raise Exception('An Error level log should not be output')

        logging.getLogger().addHandler(AbortLogHandler())

        dir_mock.side_effect = Abort

        mock_success = Mock()
        mock_error = Mock()

        work = Async(target='dir',
                     callbacks={'success': mock_success,
                                'error': mock_error})

        with _ExecutionContext(work):
            run_job()

        self.assertFalse(mock_success.called)
        self.assertFalse(mock_error.called)
        self.assertFalse(mock_start.called)

        logging.getLogger().removeHandler(AbortLogHandler())
示例#9
0
    def test_run(self, ctime):
        """Ensure tasks are run when run_queues is called."""

        from furious.async import Async
        from furious.test_stubs.appengine.queues import run as run_queues

        # Enqueue a couple of tasks
        async = Async(target='time.ctime')
        async.start()
        async2 = Async(target='time.ctime')
        async2.start()

        # Run the tasks in the queue
        run_queues(self.taskqueue_service)

        self.assertEqual(2, ctime.call_count)
示例#10
0
    def test_context_works(self):
        """Ensure using a _ExecutionContext as a context manager works."""
        from furious. async import Async
        from furious.context._execution import _ExecutionContext

        with _ExecutionContext(Async(target=dir)):
            pass
    def test_marker_not_complete_when_start_fails(self, mock_insert,
                                                  context_from_id,
                                                  check_markers):
        """Ensure if the completion handler fails to start, that the marker
        does not get marked as complete.
        """

        complete_event = Mock()
        context = Context(id="contextid",
                          callbacks={'complete': complete_event})

        context_from_id.return_value = context

        check_markers.return_value = True, False

        async = Async('foo')
        async .update_options(context_id='contextid')
        FuriousCompletionMarker(id=async .context_id, complete=False).put()

        # Simulate the task failing to start
        mock_insert.side_effect = DeadlineExceededError()

        self.assertRaises(DeadlineExceededError, _completion_checker,
                          async .id, async .context_id)

        # Marker should not have been marked complete.
        current_marker = FuriousCompletionMarker.get_by_id(async .context_id)
        self.assertFalse(current_marker.complete)
    def test_markers_and_context_complete(self, mark, context_from_id,
                                          check_markers):
        """Ensure if all markers are complete that True is returned and
        nothing else is done.
        """
        async = Async('foo')
        async .update_options(context_id='contextid')

        complete_event = Mock()
        context = Context(id="contextid",
                          callbacks={'complete': complete_event})

        context_from_id.return_value = context

        marker = FuriousCompletionMarker(id="contextid", complete=True)
        marker.put()

        check_markers.return_value = True, False
        mark.return_value = True

        result = _completion_checker(async .id, async .context_id)

        self.assertTrue(result)

        self.assertFalse(complete_event.start.called)

        marker.key.delete()
示例#13
0
    def get(self):
        from furious. async import Async

        count = int(self.request.get('tasks', 5))

        Async(insert_tasks, queue='example', args=[count]).start()
        self.response.out.write('Successfully inserted a group of Async jobs.')
示例#14
0
def state_machine_success():
    """A positive result!  Iterate!"""
    from furious. async import Async
    from furious.context import get_current_async

    result = get_current_async().result

    if result == 'ALPHA':
        logging.info('Inserting continuation for state %s.', result)
        return Async(target=complex_state_generator_alpha, args=[result])

    elif result == 'BRAVO':
        logging.info('Inserting continuation for state %s.', result)
        return Async(target=complex_state_generator_bravo, args=[result])

    logging.info('Done working, stop now.')
示例#15
0
    def add(self, target, args=None, kwargs=None, **options):
        """Add an Async job to this context.

        Takes an Async object or the arguments to construct an Async
        object as arguments.  Returns the newly added Async object.
        """
        from furious. async import Async
        from furious.batcher import Message

        if self._tasks_inserted:
            raise errors.ContextAlreadyStartedError(
                "This Context has already had its tasks inserted.")

        if not isinstance(target, (Async, Message)):
            target = Async(target, args, kwargs, **options)

        target.update_options(_context_id=self.id)

        if self.persist_async_results:
            target.update_options(persist_result=True)

        self._tasks.append(target)
        self._options['_task_ids'].append(target.id)

        return target
示例#16
0
    def test_calls_error_callback(self):
        """Ensure run_job catches any exceptions raised by the job, then calls
        the error callback.
        """
        from furious.async import Async
        from furious.context._execution import _ExecutionContext
        from furious.processors import run_job

        call_count = []
        handle_count = []

        def handle_success():
            call_count.append(1)

        def handle_errors():
            handle_count.append(1)

        work = Async(target=dir, args=[1, 2],
                     callbacks={'success': handle_success,
                                'error': handle_errors})

        with _ExecutionContext(work):
            run_job()

        self.assertEqual(1, len(handle_count),
                         "Error handler called wrong number of times.")
        self.assertEqual(0, len(call_count),
                         "Success handler unexpectedly called.")
示例#17
0
文件: job.py 项目: lyddonb/contention
def start(number_of_items):
    logging.info("******** Starting the process. ******** ")
    job_id = uuid.uuid4().hex
    logging.info("******* JOB ID: {}.".format(job_id))

    start_time = _get_current_datetime_as_string()

    rs = RunState(id=job_id)
    rs.count_map = {}

    cs = CompleteState(id=job_id)
    cs.number_of_items = number_of_items
    cs.complete = False

    ndb.put_multi([rs, cs])

    with context.new() as ctx:
        ctx.set_event_handler('complete', Async(
            completion_handler, args=[job_id, start_time]))

        for i in xrange(number_of_items):
            logging.info("###### JOB ITEM: {}.".format(i))
            ctx.add(target=run_process,
                    args=[job_id, i, _get_current_datetime_as_string()])

    logging.info("###### JOBS STARTED")

    return job_id
示例#18
0
    def test_get_empty_task_args(self):
        """Ensure get_task_args returns {} if no task_args."""
        from furious. async import Async

        job = Async('nonexistant')

        self.assertEqual({}, job.get_task_args())
示例#19
0
    def test_get_empty_headers(self):
        """Ensure get_headers returns the job headers."""
        from furious. async import Async

        job = Async('nonexistant')

        self.assertEqual({}, job.get_headers())
示例#20
0
    def test_get_default_queue(self):
        """Ensure get_queue returns the default queue if non was given."""
        from furious. async import Async

        job = Async('nonexistant')

        self.assertEqual('default', job.get_queue())
示例#21
0
    def test_init_opts_supersede_decorated_options(self):
        """Ensure options passed to init override decorated options."""
        from furious. async import Async
        from furious. async import defaults

        options = {
            'value': 1,
            'other': 'zzz',
            'nested': {
                1: 1
            },
            'id': 'wrong',
            'context_id': None,
            'parent_id': 'parentid'
        }

        @defaults(**options.copy())
        def some_function():
            pass

        job = Async(some_function, value=17, other='abc', id='correct')

        options['value'] = 17
        options['other'] = 'abc'
        options['id'] = 'correct'

        options['job'] = ("furious.tests.test_async.some_function", None, None)
        options['_recursion'] = {'current': 0, 'max': 100}

        self.assertEqual(options, job._options)
示例#22
0
    def test_update_options_supersede_init_opts(self):
        """Ensure update_options supersedes the options set in init."""
        from furious. async import Async

        options = {
            'value': 1,
            'other': 'zzz',
            'nested': {
                1: 1
            },
            'id': 'wrong',
            'context_id': None,
            'parent_id': 'parentid'
        }

        job = Async("nonexistant", **options.copy())

        job.update_options(value=23, other='stuff', id='right')

        options['value'] = 23
        options['other'] = 'stuff'
        options['id'] = 'right'

        options['job'] = ("nonexistant", None, None)

        options['_recursion'] = {'current': 0, 'max': 100}

        self.assertEqual(options, job._options)
示例#23
0
    def test_decorated_options(self):
        """Ensure the defaults decorator sets Async options."""
        from furious. async import Async
        from furious. async import defaults

        options = {
            'value': 1,
            'other': 'zzz',
            'nested': {
                1: 1
            },
            'id': 'thing',
            'context_id': None,
            'parent_id': 'parentid'
        }

        @defaults(**options.copy())
        def some_function():
            pass

        job = Async(some_function)

        options['job'] = ("furious.tests.test_async.some_function", None, None)
        options['_recursion'] = {'current': 0, 'max': 100}

        self.assertEqual(options, job._options)
示例#24
0
    def test_context_id(self):
        """Ensure context_id returns the context_id."""
        from furious. async import Async

        job = Async('somehting')
        job.update_options(context_id='blarghahahaha')
        self.assertEqual(job.context_id, 'blarghahahaha')
示例#25
0
    def test_deepcopy(self):
        """Make sure you can deepcopy an Async."""
        import copy

        from furious. async import Async

        job = Async(dir)
        copy.deepcopy(job)
示例#26
0
    def test_uses_given_id(self):
        """Ensure an id passed in is used."""
        from furious. async import Async

        job = Async('somehting', id='superrandom')

        self.assertEqual(job.id, 'superrandom')
        self.assertEqual(job.get_options()['id'], 'superrandom')
示例#27
0
    def test_no_args_with_kwargs(self):
        """Ensure no args with kwargs generate a well-formed job tuple."""
        from furious. async import Async

        job = ("test", None, {'a': 1, 'b': 'c', 'alpha': True})
        async_job = Async(*job)

        self.assertEqual(job, async_job.job)
示例#28
0
    def test_args_with_no_kwargs(self):
        """Ensure args and no kwargs generate a well-formed job tuple."""
        from furious. async import Async

        job = ("test", (1, 2, 3))
        async_job = Async(*job)

        self.assertEqual(job + (None, ), async_job.job)
示例#29
0
    def test_no_comletion(self):
        """Ensure does not fail if there's no completion checker."""
        from furious.async import Async
        from furious.processors import _handle_context_completion_check

        async = Async(dir)

        _handle_context_completion_check(async)
示例#30
0
    def test_job_params(self):
        """Ensure good args and kwargs generate a well-formed job tuple."""
        from furious. async import Async

        job = ("test", [1, 2, 3], {'a': 1, 'b': 2, 'c': 3})
        async_job = Async(*job)

        self.assertEqual(job, async_job.job)