def test_stats_router(self): """ Checking that the pool executor version of the router delivers signals as intended """ from nio.common.block.router.stats_router import StatsRouter block_router = StatsRouter() context = BlockContext(block_router, dict(), dict(), None, service_name="TestStatsRouterServiceName") # create blocks sender_block = BlockController(SenderBlock) sender_block.configure(context) receiver_block = BlockController(ReceiverBlock) receiver_block.configure(context) receiver_block2 = BlockController(ReceiverBlock2) receiver_block2.configure(context) # create a management subscriber subscriber = Subscriber(self._on_stats, **self._topics) subscriber.open() sleep(0.5) # create context initialization data receiver_blocks = 2 blocks = AttributeDict(receiverblock=receiver_block, receiverblock2=receiver_block2, senderblock=sender_block) execution = [AttributeDict(name="senderblock", receivers=["receiverblock", "receiverblock2"])] router_context = RouterContext(execution, blocks) block_router.configure(router_context) block_router.start() signals_count = 0 self._received_signals = 0 for i in range(0, 50): signals = [] for j in range(0, i): signals.append(j) signals_count += 1 sender_block.process_signals(signals) sleep(0.02) sleep(0.1) self.assertEqual(signals_count * receiver_blocks, self._received_signals) print('Received a total of: {0} signals'. format(self._received_signals)) block_router.stop()
class LocalSubscriber(GeneratorBlock): """ A block for subscribing to a local nio communication channel. Functions regardless of communication module implementation. Unlike the regular Subscriber block, the one does not need data to be json """ version = VersionProperty("0.1.1") topic = StringProperty(title='Topic', default="") local_identifier = StringProperty(title='Local Identifier', default='[[INSTANCE_ID]]', visible=False) def __init__(self): super().__init__() self._subscriber = None def configure(self, context): super().configure(context) self._subscriber = NioSubscriber(self._subscriber_handler, topic="{}.{}".format( self.local_identifier(), self.topic())) def start(self): """ Start the block by opening the underlying subscriber """ super().start() self._subscriber.open() def stop(self): """ Stop the block by closing the underlying subscriber """ self._subscriber.close() super().stop() def _subscriber_handler(self, signals): try: signals = b64decode(signals[0].signals) signals = pickle.loads(signals) except pickle.UnpicklingError: self.logger.exception("Unpickling based pickle error") except TypeError: self.logger.exception("Unable to decode pickled signals") except: self.logger.exception("Error handling signals") else: self.notify_signals(signals)
class Subscriber(Block): """ A block for subscribing to a NIO communication channel. Functions regardless of communication module implementation. Properties: topic (str): Defines topic to subscribe to in order to receive signals. """ topic = StringProperty(title='Topic') def __init__(self): super().__init__() self._subscriber = None def configure(self, context): super().configure(context) self._subscriber = NIOSubscriber(self.process_signals, topic=self.topic()) def start(self): """ Start the block by opening the underlying subscriber """ super().start() self._subscriber.open() def stop(self): """ Stop the block by closing the underlying subscriber """ self._subscriber.close() super().stop() def process_signals(self, signals): """ Subscriber block doesn't do any real processing. Just passes incoming signals along to any receivers. """ self.notify_signals(signals)
def _setup_pubsub(self): # Supscribe to published signals for publisher_topic in self.publisher_topics(): self._subscribers[publisher_topic] = \ Subscriber(self._published_signals, topic=publisher_topic) for subscriber in self._subscribers: self._subscribers[subscriber].open() # Allow tests to publish to subscribers in service for subscriber_topic in self.subscriber_topics(): self._publishers[subscriber_topic] = \ Publisher(topic=subscriber_topic) for publisher in self._publishers: self._publishers[publisher].open()
class LocalSubscriber(PubSubConnectivity, GeneratorBlock): """ A block for subscribing to a local nio communication channel. Functions regardless of communication module implementation. Unlike the regular Subscriber block, the one does not need data to be json """ version = VersionProperty("1.1.0") topic = StringProperty(title='Topic', default="") local_identifier = StringProperty(title='Local Identifier', default='[[INSTANCE_ID]]', visible=False) def __init__(self): super().__init__() self._subscriber = None def configure(self, context): super().configure(context) self._subscriber = NioSubscriber(self._subscriber_handler, topic="{}.{}".format( self.local_identifier(), self.topic())) try: self._subscriber.open(on_connected=self.conn_on_connected, on_disconnected=self.conn_on_disconnected) except TypeError as e: self.logger.warning( "Connecting to an outdated communication module") # try previous interface self._subscriber.open() # no need to configure connectivity if not supported return # let connectivity configure self.conn_configure(self._subscriber.is_connected) def stop(self): """ Stop the block by closing the underlying subscriber """ self._subscriber.close() super().stop() def _subscriber_handler(self, signals): try: signals = b64decode(signals[0].signals) signals = pickle.loads(signals) except pickle.UnpicklingError: self.logger.exception("Unpickling based pickle error") except TypeError: self.logger.exception("Unable to decode pickled signals") except: self.logger.exception("Error handling signals") else: self.notify_signals(signals)
def configure(self, context): super().configure(context) self._subscriber = NioSubscriber(self._subscriber_handler, topic=self.topic()) try: self._subscriber.open(on_connected=self.conn_on_connected, on_disconnected=self.conn_on_disconnected) except TypeError as e: self.logger.warning( "Connecting to an outdated communication module") # try previous interface self._subscriber.open() # no need to configure connectivity if not supported return # let connectivity configure self.conn_configure(self._subscriber.is_connected)
def configure(self, context): super().configure(context) topic = self.topic() # If a local identifier was included use it as a prefix if self.local_identifier(): topic = "{}.{}".format(self.local_identifier(), topic) self._subscriber = NioSubscriber(self._subscriber_handler, topic=topic) try: self._subscriber.open(on_connected=self.conn_on_connected, on_disconnected=self.conn_on_disconnected) except TypeError as e: self.logger.warning( "Connecting to an outdated communication module") # try previous interface self._subscriber.open() # no need to configure connectivity if not supported return # let connectivity configure self.conn_configure(self._subscriber.is_connected)
class Subscriber(PubSubConnectivity, GeneratorBlock): """ A block for subscribing to a nio communication channel. Functions regardless of communication module implementation. Properties: topic (str): Defines topic to subscribe to in order to receive signals. """ version = VersionProperty("1.1.1") topic = StringProperty(title="Topic", default="") def __init__(self): super().__init__() self._subscriber = None def configure(self, context): super().configure(context) self._subscriber = NioSubscriber(self._subscriber_handler, topic=self.topic()) try: self._subscriber.open(on_connected=self.conn_on_connected, on_disconnected=self.conn_on_disconnected) except TypeError as e: self.logger.warning( "Connecting to an outdated communication module") # try previous interface self._subscriber.open() # no need to configure connectivity if not supported return # let connectivity configure self.conn_configure(self._subscriber.is_connected) def stop(self): """ Stop the block by closing the underlying subscriber """ self._subscriber.close() super().stop() def _subscriber_handler(self, signals): self.notify_signals(signals)
def configure(self, context): super().configure(context) self._subscriber = NioSubscriber(self._subscriber_handler, topic="{}.{}".format( self.local_identifier(), self.topic()))
class LocalSubscriber(PubSubConnectivity, GeneratorBlock): """ A block for subscribing to a local nio communication channel. Functions regardless of communication module implementation. Unlike the regular Subscriber block, the one does not need data to be json """ version = VersionProperty("1.1.1") topic = StringProperty(title="Topic", default="") local_identifier = StringProperty(title='Local Identifier', default='[[INSTANCE_ID]]', advanced=True) def __init__(self): super().__init__() self._subscriber = None def configure(self, context): super().configure(context) topic = self.topic() # If a local identifier was included use it as a prefix if self.local_identifier(): topic = "{}.{}".format(self.local_identifier(), topic) self._subscriber = NioSubscriber(self._subscriber_handler, topic=topic) try: self._subscriber.open(on_connected=self.conn_on_connected, on_disconnected=self.conn_on_disconnected) except TypeError as e: self.logger.warning( "Connecting to an outdated communication module") # try previous interface self._subscriber.open() # no need to configure connectivity if not supported return # let connectivity configure self.conn_configure(self._subscriber.is_connected) def stop(self): """ Stop the block by closing the underlying subscriber """ self._subscriber.close() super().stop() def _subscriber_handler(self, signals): try: signals = b64decode(signals[0].signals) signals = pickle.loads(signals) except pickle.UnpicklingError: self.logger.exception("Unpickling based pickle error") except AttributeError: # It's possible these came from a non-local publisher # This would occur in service tests or if a regular publisher # wanted to publish to a local topic. In the non-service test # case this would generally indicate bad service design but we # don't want to explicitly prevent/forbid it if (signals and isinstance(signals, list) and isinstance(signals[0], Signal)): self.notify_signals(signals) else: raise except TypeError: self.logger.exception("Unable to decode pickled signals") except Exception: self.logger.exception("Error handling signals") else: self.notify_signals(signals)
def configure(self, context): super().configure(context) self._subscriber = NIOSubscriber(self.process_signals, topic=self.topic())