Ejemplo n.º 1
0
    def test_handle_prompt_failed(self):
        process = ProcessApplication.mixin(self.infrastructure_class)(
            name="test",
            policy=example_policy,
            persist_event_type=ExampleAggregate.Event,
            setup_table=True,
        )

        def raise_exception(_):
            raise Exception()

        def raise_prompt_failed(_):
            raise PromptFailed()

        subscribe(raise_exception)
        try:
            with self.assertRaises(PromptFailed):
                process.publish_prompt()
        finally:
            unsubscribe(raise_exception)

        subscribe(raise_prompt_failed)
        try:
            with self.assertRaises(PromptFailed):
                process.publish_prompt()
        finally:
            unsubscribe(raise_prompt_failed)

        try:
            process.publish_prompt()
        finally:
            process.close()
Ejemplo n.º 2
0
    def close(self):
        super(InProcessRunner, self).close()

        unsubscribe(
            predicate=self.system.is_prompt,
            handler=self.handle_prompt,
        )
Ejemplo n.º 3
0
    def test_handle_prompt_failed(self):
        process = Process(
            'test',
            policy=example_policy,
            persist_event_type=ExampleAggregate.Event,
            setup_tables=True,
        )

        def raise_exception(_):
            raise Exception()

        def raise_prompt_failed(_):
            raise PromptFailed()

        subscribe(raise_exception)
        try:
            with self.assertRaises(PromptFailed):
                process.publish_prompt()
        finally:
            unsubscribe(raise_exception)

        subscribe(raise_prompt_failed)
        try:
            with self.assertRaises(PromptFailed):
                process.publish_prompt()
        finally:
            unsubscribe(raise_prompt_failed)

        try:
            process.publish_prompt()
        finally:
            process.close()
Ejemplo n.º 4
0
 def close(self):
     if self.persistence_policy:
         unsubscribe(
             predicate=self.persistence_policy.is_event,
             handler=self.publish_prompt,
         )
     super(ProcessApplication, self).close()
Ejemplo n.º 5
0
    def run(self):
        # Construct process application object.
        self.process = self.application_process_class(
            pipeline_id=self.pipeline_id,
            notification_log_section_size=self.notification_log_section_size,
            pool_size=self.pool_size,
            setup_table=self.setup_tables,
        )

        # Follow upstream notification logs.
        for upstream_name in self.upstream_names:

            # Obtain a notification log object (local or remote) for the upstream process.
            if upstream_name == self.process.name:
                # Upstream is this process's application,
                # so use own notification log.
                notification_log = self.process.notification_log
            else:
                # For a different application, we need to construct a notification
                # log with a record manager that has the upstream application ID.
                # Currently assumes all applications are using the same database
                # and record manager class. If it wasn't the same database,we would
                # to use a remote notification log, and upstream would need to provide
                # an API from which we can pull. It's not unreasonable to have a fixed
                # number of application processes connecting to the same database.
                record_manager = self.process.event_store.record_manager
                notification_log = RecordManagerNotificationLog(
                    record_manager=record_manager.clone(
                        application_name=upstream_name,
                        pipeline_id=self.pipeline_id),
                    section_size=self.process.notification_log_section_size)
                # Todo: Support upstream partition IDs different from self.pipeline_id.
                # Todo: Support combining partitions. Read from different partitions but write to the same partition,
                # could be one os process that reads from many logs of the same upstream app, or many processes each
                # reading one partition with contention writing to the same partition).
                # Todo: Support dividing partitions Read from one but write to many. Maybe one process per
                # upstream partition, round-robin to pick partition for write. Or have many processes reading
                # with each taking it in turn to skip processing somehow.
                # Todo: Dividing partitions would allow a stream to flow at the same rate through slower
                # process applications.
                # Todo: Support merging results from "replicated state machines" - could have a command
                # logging process that takes client commands and presents them in a notification log.
                # Then the system could be deployed in different places, running independently, receiving
                # the same commands, and running the same processes. The command logging process could
                # be accompanied with a result logging process that reads results from replicas as they
                # are available. Not sure what to do if replicas return different things. If one replica
                # goes down, then it could resume by pulling events from another? Not sure what to do.
                # External systems could be modelled as commands.

            # Make the process follow the upstream notification log.
            self.process.follow(upstream_name, notification_log)

        # Subscribe to broadcast prompts published by the process application.
        subscribe(handler=self.broadcast_prompt, predicate=self.is_prompt)

        try:
            self.loop_on_prompts()
        finally:
            unsubscribe(handler=self.broadcast_prompt,
                        predicate=self.is_prompt)
Ejemplo n.º 6
0
    def test_publish_subscribe_unsubscribe(self):
        # Check subscribing event handlers with predicates.
        # - when predicate is True, handler should be called
        event = mock.Mock()
        predicate = mock.Mock()
        handler = mock.Mock()

        # When predicate is True, handler should be called ONCE.
        subscribe(event_predicate=predicate, subscriber=handler)
        publish(event)
        predicate.assert_called_once_with(event)
        handler.assert_called_once_with(event)

        # When predicate is True, after unsubscribing, handler should NOT be called again.
        unsubscribe(event_predicate=predicate, subscriber=handler)
        publish(event)
        predicate.assert_called_once_with(event)
        handler.assert_called_once_with(event)

        # When predicate is False, handler should NOT be called.
        predicate = lambda x: False
        handler = mock.Mock()
        subscribe(event_predicate=predicate, subscriber=handler)
        publish(event)
        self.assertEqual(0, handler.call_count)
Ejemplo n.º 7
0
 def stop(self):
     """
     Stops the process.
     """
     self.has_been_stopped.set()
     self.process_application.close()
     unsubscribe(handler=self._enqueue_prompt_to_pull,
                 predicate=is_prompt_to_pull)
Ejemplo n.º 8
0
    def close(self):
        unsubscribe(handler=self.broadcast_prompt, predicate=self.is_prompt)

        for os_process in self.os_processes:
            os_process.inbox.put('QUIT')

        for os_process in self.os_processes:
            os_process.join(timeout=10)

        for os_process in self.os_processes:
            os_process.is_alive() and os_process.terminate()

        self.os_processes = None
        self.manager = None
Ejemplo n.º 9
0
    def init_process(self, msg):
        self.pipeline_actor = msg.pipeline_actor
        self.downstream_actors = msg.downstream_actors
        self.pipeline_id = msg.pipeline_id
        self.upstream_application_names = msg.upstream_application_names

        # Construct the process application class.
        process_class = msg.process_application_class
        if msg.infrastructure_class:
            process_class = process_class.mixin(msg.infrastructure_class)

        # Reset the database connection (for Django).
        process_class.reset_connection_after_forking()

        # Construct the process application.
        self.process = process_class(pipeline_id=self.pipeline_id)
        assert isinstance(self.process, ProcessApplication)

        # Subscribe the slave actor's send_prompt() method.
        #  - the process application will call publish_prompt()
        #    and the actor will receive the prompt and send it
        #    as a message.
        subscribe(predicate=self.is_my_prompt, handler=self.send_prompt)

        # Close the process application persistence policy.
        #  - slave actor process application doesn't publish
        #    events, so we don't need this
        self.process.persistence_policy.close()

        # Unsubscribe process application's publish_prompt().
        #  - slave actor process application doesn't publish
        #    events, so we don't need this
        unsubscribe(
            predicate=self.process.persistence_policy.is_event,
            handler=self.process.publish_prompt_for_events,
        )

        # Construct and follow upstream notification logs.
        for upstream_application_name in self.upstream_application_names:
            record_manager = self.process.event_store.record_manager
            # assert isinstance(record_manager, ACIDRecordManager), type(record_manager)
            notification_log = RecordManagerNotificationLog(
                record_manager=record_manager.clone(
                    application_name=upstream_application_name,
                    pipeline_id=self.pipeline_id,
                ),
                section_size=self.process.notification_log_section_size,
            )
            self.process.follow(upstream_application_name, notification_log)
Ejemplo n.º 10
0
    def close(self) -> None:
        super(MultiprocessRunner, self).close()

        unsubscribe(handler=self.broadcast_prompt, predicate=is_prompt_to_pull)

        for os_process in self.os_processes:
            os_process.inbox.put(PromptToQuit())

        for os_process in self.os_processes:
            os_process.join(timeout=10)

        for os_process in self.os_processes:
            if os_process.is_alive():
                os_process.terminate()

        self.os_processes.clear()
Ejemplo n.º 11
0
    def test_publish_subscribe_unsubscribe(self):
        # Check subscribing event handlers with predicates.
        # - when predicate is True, handler should be called
        event = mock.Mock()
        predicate = mock.Mock()
        handler = mock.Mock()

        # Check we can assert there are no event handlers subscribed.
        assert_event_handlers_empty()

        # When predicate is True, handler should be called ONCE.
        subscribe(handler=handler, predicate=predicate)

        # Check we can assert there are event handlers subscribed.
        self.assertRaises(EventHandlersNotEmptyError,
                          assert_event_handlers_empty)

        # Check what happens when an event is published.
        publish(event)
        predicate.assert_called_once_with(event)
        handler.assert_called_once_with(event)

        # When predicate is True, after unsubscribing, handler should NOT be called again.
        unsubscribe(handler=handler, predicate=predicate)
        publish(event)
        predicate.assert_called_once_with(event)
        handler.assert_called_once_with(event)

        # Check we can assert there are no event handlers subscribed.
        assert_event_handlers_empty()

        # When predicate is False, handler should NOT be called.
        predicate = lambda x: False
        handler = mock.Mock()
        subscribe(handler=handler, predicate=predicate)
        publish(event)
        self.assertEqual(0, handler.call_count)

        # Unsubscribe.
        unsubscribe(handler=handler, predicate=predicate)

        # Check we can assert there are no event handlers subscribed.
        assert_event_handlers_empty()
Ejemplo n.º 12
0
    def test_publish_subscribe_unsubscribe(self):
        # Check subscribing event handlers with predicates.
        # - when predicate is True, handler should be called
        event = mock.Mock()
        predicate = mock.Mock()
        handler = mock.Mock()

        # Check we can assert there are no event handlers subscribed.
        assert_event_handlers_empty()

        # When predicate is True, handler should be called ONCE.
        subscribe(handler=handler, predicate=predicate)

        # Check we can assert there are event handlers subscribed.
        self.assertRaises(EventHandlersNotEmptyError, assert_event_handlers_empty)

        # Check what happens when an event is published.
        publish(event)
        predicate.assert_called_once_with(event)
        handler.assert_called_once_with(event)

        # When predicate is True, after unsubscribing, handler should NOT be called again.
        unsubscribe(handler=handler, predicate=predicate)
        publish(event)
        predicate.assert_called_once_with(event)
        handler.assert_called_once_with(event)

        # Check we can assert there are no event handlers subscribed.
        assert_event_handlers_empty()

        # When predicate is False, handler should NOT be called.
        predicate = lambda x: False
        handler = mock.Mock()
        subscribe(handler=handler, predicate=predicate)
        publish(event)
        self.assertEqual(0, handler.call_count)

        # Unsubscribe.
        unsubscribe(handler=handler, predicate=predicate)

        # Check we can assert there are no event handlers subscribed.
        assert_event_handlers_empty()
Ejemplo n.º 13
0
 def stop(self):
     """
     Stops the process.
     """
     # print("%s actor stopping %s" % (os.getpid(), datetime.datetime.now()))
     self.has_been_stopped.set()
     # print("%s actor joining db_jobs_thread %s" % (os.getpid(),
     #                                            datetime.datetime.now()))
     self.db_jobs_queue.put(None)
     self.upstream_event_queue.put(None)
     self.downstream_prompt_queue.put(None)
     self._has_been_prompted.set()
     self.positions_initialised.set()
     self.db_jobs_thread.join(timeout=1)
     assert not self.db_jobs_thread.is_alive(), (
         "DB jobs thread still alive")
     # print("%s actor joining process_events_thread %s" % (os.getpid(),
     #                                            datetime.datetime.now()))
     self.process_events_thread.join(timeout=1)
     assert not self.process_events_thread.is_alive(), (
         "Process events thread still alive")
     # print("%s actor joining process_prompts_thread %s" % (os.getpid(),
     #                                            datetime.datetime.now()))
     self.process_prompts_thread.join(timeout=1)
     assert not self.process_prompts_thread.is_alive(), (
         "Process prompts thread still alive")
     # print("%s actor joining push_prompts_thread %s" % (os.getpid(),
     #                                            datetime.datetime.now()))
     self.push_prompts_thread.join(timeout=1)
     assert not self.push_prompts_thread.is_alive(), (
         "Push prompts thread still alive")
     self.process_application.close()
     unsubscribe(handler=self._enqueue_prompt_to_pull,
                 predicate=is_prompt_to_pull)
     # print("%s actor stopped %s" % (os.getpid(), datetime.datetime.now()))
     ray.actor.exit_actor()
Ejemplo n.º 14
0
 def close(self):
     unsubscribe(self.contract_specification_created,
                 self.generate_dependency_graph)
Ejemplo n.º 15
0
 def close(self):
     unsubscribe(self.add_list_to_collection, self.is_list_started)
     unsubscribe(self.remove_list_from_collection, self.is_list_discarded)
Ejemplo n.º 16
0
 def tearDown(self):
     unsubscribe(*self.subscription)
     assert_event_handlers_empty()
Ejemplo n.º 17
0
 def close(self):
     """Stops all the actors running a system of process applications."""
     super(ActorModelRunner, self).close()
     unsubscribe(handler=self.forward_prompt, predicate=self.is_prompt)
     if self.shutdown_on_close:
         self.shutdown()
Ejemplo n.º 18
0
 def close(self):
     unsubscribe(self.market_simulation_created,
                 self.generate_simulated_prices_for_market_simulation)
Ejemplo n.º 19
0
 def close(self):
     unsubscribe(predicate=self.is_upstream_prompt, handler=self.run)
     unsubscribe(predicate=self.persistence_policy.is_event, handler=self.publish_prompt_from_event)
     super(ProcessApplication, self).close()
Ejemplo n.º 20
0
 def close(self):
     unsubscribe(self.is_call_dependencies_created, self.cache_dependencies)
     unsubscribe(self.is_call_dependents_created, self.cache_dependents)
     unsubscribe(self.is_call_result_created, self.cache_result)
     unsubscribe(self.is_call_result_discarded, self.purge_result)
Ejemplo n.º 21
0
 def close(self):
     unsubscribe(self.store_event, self.is_event)
Ejemplo n.º 22
0
 def unsubscribe(self):
     unsubscribe(self.is_call_requirement_created, self.print_compilation_progress)
     unsubscribe(self.is_calculating, self.check_is_timed_out)
     unsubscribe(self.is_calculating, self.check_is_interrupted)
     unsubscribe(self.is_evaluation_complete, self.set_is_finished)
     unsubscribe(self.is_result_value_computed, self.inc_result_value_computed_count)
     unsubscribe(self.is_result_value_computed, self.print_evaluation_progress)
     unsubscribe(self.is_call_result_created, self.inc_call_result_count)
     unsubscribe(self.is_call_result_created, self.print_evaluation_progress)
Ejemplo n.º 23
0
 def close(self):
     unsubscribe(self.is_domain_event, self.store_domain_event)
Ejemplo n.º 24
0
 def close(self):
     unsubscribe(self.is_call_dependencies_created, self.cache_dependencies)
     unsubscribe(self.is_call_dependents_created, self.cache_dependents)
     unsubscribe(self.is_call_result_created, self.cache_result)
     unsubscribe(self.is_call_result_discarded, self.purge_result)
Ejemplo n.º 25
0
 def close(self):
     unsubscribe(self.add_user_to_collection, self.is_user_created)
     unsubscribe(self.remove_user_from_collection, self.is_user_discarded)
Ejemplo n.º 26
0
 def close(self):
     unsubscribe(predicate=self.trigger, handler=self.take_snapshot)
Ejemplo n.º 27
0
 def close(self):
     unsubscribe(self.store_event, self.is_event)
Ejemplo n.º 28
0
    def close(self) -> None:
        super(InProcessRunner, self).close()

        unsubscribe(predicate=is_prompt_to_pull, handler=self.handle_prompt)
 def close(self) -> None:
     unsubscribe(self.add_ticket, self.is_ticket_created)
     unsubscribe(self.update_ticket, self.is_ticket_updated)
     unsubscribe(self.delete_ticket, self.is_ticket_deleted)
Ejemplo n.º 30
0
 def close(self):
     unsubscribe(self.is_contract_valuation_created, self.generate_contract_valuation)
Ejemplo n.º 31
0
 def close(self):
     unsubscribe(self.contract_specification_created, self.generate_dependency_graph)
     unsubscribe(self.call_requirement_created, self.limit_calls)
Ejemplo n.º 32
0
    def test_attribute(self):
        # Check we get an error when called with something other than a function.
        self.assertRaises(ProgrammingError, attribute, 'not a getter')
        self.assertRaises(ProgrammingError, attribute, 123)
        self.assertRaises(ProgrammingError, attribute, None)

        # Call the decorator with a function.
        getter = lambda: None
        p = attribute(getter)

        # Check we got a property object.
        self.assertIsInstance(p, property)

        # Check the property object has both setter and getter functions.
        self.assertTrue(p.fset)
        self.assertTrue(p.fget)

        # Pretend we decorated an object.
        entity_id = uuid4()
        o = VersionedEntity(id=entity_id, __version__=0)
        o.__dict__['_<lambda>'] = 'value1'

        # Call the property's getter function.
        value = p.fget(o)
        self.assertEqual(value, 'value1')

        # Call the property's setter function.
        p.fset(o, 'value2')

        # Check the attribute has changed.
        value = p.fget(o)
        self.assertEqual(value, 'value2')

        # Check the property's getter function isn't the getter function we passed in.
        self.assertNotEqual(p.fget, getter)

        # Define a class that uses the decorator.
        class Aaa(VersionedEntity):
            "An event sourced entity."

            def __init__(self, a, *args, **kwargs):
                super(Aaa, self).__init__(*args, **kwargs)
                self._a = a

            @attribute
            def a(self):
                "A mutable event sourced property."

        # Instantiate the class and check assigning to the property publishes an event and updates the object state.
        published_events = []
        subscription = (lambda x: True, lambda x: published_events.append(x))
        subscribe(*subscription)
        entity_id = uuid4()
        try:
            aaa = Aaa(id=entity_id, __version__=1, a=1)
            self.assertEqual(aaa.a, 1)
            aaa.a = 'value1'
            self.assertEqual(aaa.a, 'value1')
        finally:
            unsubscribe(*subscription)

        # Check an event was published.
        self.assertEqual(len(published_events), 1)

        # Check the published event was an AttributeChanged event, with the expected attribute values.
        published_event = published_events[0]
        self.assertIsInstance(published_event, AttributeChanged)
        self.assertEqual(published_event.name, '_a')
        self.assertEqual(published_event.value, 'value1')
        self.assertTrue(published_event.originator_version, 1)
        self.assertEqual(published_event.originator_id, entity_id)
Ejemplo n.º 33
0
 def tearDown(self):
     unsubscribe(*self.subscription)
     assert_event_handlers_empty()
Ejemplo n.º 34
0
    def close(self):
        unsubscribe(predicate=self.is_my_prompt, handler=self.send_prompt)

        self.process.close()
Ejemplo n.º 35
0
 def close(self):
     unsubscribe(self.contract_specification_created, self.generate_dependency_graph)
Ejemplo n.º 36
0
    def test_attribute(self):
        # Check we get an error when called with something other than a function.
        self.assertRaises(ProgrammingError, attribute, 'not a getter')
        self.assertRaises(ProgrammingError, attribute, 123)
        self.assertRaises(ProgrammingError, attribute, None)

        # Call the decorator with a function.
        getter = lambda: None
        p = attribute(getter)

        # Check we got a property object.
        self.assertIsInstance(p, property)

        # Check the property object has both setter and getter functions.
        self.assertTrue(p.fset)
        self.assertTrue(p.fget)

        # Pretend we decorated an object.
        entity_id = uuid4()
        o = VersionedEntity(originator_id=entity_id, originator_version=0)
        o.__dict__['_<lambda>'] = 'value1'

        # Call the property's getter function.
        value = p.fget(o)
        self.assertEqual(value, 'value1')

        # Call the property's setter function.
        p.fset(o, 'value2')

        # Check the attribute has changed.
        value = p.fget(o)
        self.assertEqual(value, 'value2')

        # Check the property's getter function isn't the getter function we passed in.
        self.assertNotEqual(p.fget, getter)

        # Define a class that uses the decorator.
        class Aaa(VersionedEntity):
            "An event sourced entity."

            def __init__(self, a, *args, **kwargs):
                super(Aaa, self).__init__(*args, **kwargs)
                self._a = a

            @attribute
            def a(self):
                "A mutable event sourced property."

        # Instantiate the class and check assigning to the property publishes an event and updates the object state.
        published_events = []
        subscription = (lambda x: True, lambda x: published_events.append(x))
        subscribe(*subscription)
        entity_id = uuid4()
        try:
            aaa = Aaa(originator_id=entity_id, originator_version=1, a=1)
            self.assertEqual(aaa.a, 1)
            aaa.a = 'value1'
            self.assertEqual(aaa.a, 'value1')
        finally:
            unsubscribe(*subscription)

        # Check an event was published.
        self.assertEqual(len(published_events), 1)

        # Check the published event was an AttributeChanged event, with the expected attribute values.
        published_event = published_events[0]
        self.assertIsInstance(published_event, AttributeChanged)
        self.assertEqual(published_event.name, '_a')
        self.assertEqual(published_event.value, 'value1')
        self.assertTrue(published_event.originator_version, 1)
        self.assertEqual(published_event.originator_id, entity_id)
Ejemplo n.º 37
0
 def close(self):
     unsubscribe(self.is_contract_valuation_created,
                 self.generate_contract_valuation)
Ejemplo n.º 38
0
 def close(self):
     unsubscribe(predicate=self.condition, handler=self.take_snapshot)
Ejemplo n.º 39
0
 def close(self):
     unsubscribe(self.market_simulation_created, self.generate_simulated_prices_for_market_simulation)