def execute(self, context: Context): waiter_timeout = asyncio.async(asyncio.sleep(context.const.waiter_timeout)) with auto_cancellation([waiter_timeout]): while True: reading = asyncio.async(self._take_message(context)) done, pending = yield from asyncio.wait([waiter_timeout, reading], return_when=concurrent.futures.FIRST_COMPLETED) reading.cancel() if waiter_timeout in done: self._logger.info('Token was lost!') context.state = LooserState() return if reading in done: message = yield from reading self._logger.debug('Message: {}.'.format(message.type)) if message.type == MessageType.TOKEN_IS_HERE: waiter_timeout.cancel() waiter_timeout = asyncio.async(asyncio.sleep(context.const.waiter_timeout)) elif message.type == MessageType.TAKE_TOKEN: context.update_token(message.token, message.data) context.state = OwnerState() return elif message.type == MessageType.WHERE_IS_TOKEN: wrap_exc(asyncio.async(context.send_response(message, MessageType.TOKEN_WAS_HERE_RECENTLY)), self._logger)
def execute(self, context: Context): self._logger.info('Token is here... Calculating...') yield from context.send_broadcast(MessageType.TOKEN_IS_HERE) heart_beat_timeout = asyncio.async(asyncio.sleep(context.const.heartbeat_timeout)) calculating = asyncio.async(context.calculate()) transferring_token = None with auto_cancellation([heart_beat_timeout, calculating, calculating, transferring_token]): while True: reading = asyncio.async(self._take_message(context)) fs = [heart_beat_timeout, reading] if transferring_token is None: fs.append(calculating) else: fs.append(transferring_token) done, pending = yield from asyncio.wait(fs, return_when=concurrent.futures.FIRST_COMPLETED) reading.cancel() if heart_beat_timeout in done: self._logger.debug('Token is here...') yield from context.send_broadcast(MessageType.TOKEN_IS_HERE) heart_beat_timeout = asyncio.async(asyncio.sleep(context.const.heartbeat_timeout)) if calculating in done: self._logger.info('Calculation finished!') self._logger.info('Transferring token...') calculating = None transferring_token = wrap_exc(asyncio.async(context.send_message_to_next(MessageType.TAKE_TOKEN)), self._logger) if transferring_token in done: success = yield from transferring_token if success: context.state = WaiterState() return else: self._logger.warn('Transferring token failed, transferring token again...') transferring_token = wrap_exc(asyncio.async(context.send_message_to_next(MessageType.TAKE_TOKEN)), self._logger) if reading in done: message = yield from reading self._logger.debug('Message: {}.'.format(message.type)) if message.type == MessageType.TOKEN_IS_HERE: if message.token.priority() > context.current_token.priority(): wrap_exc(asyncio.async(context.send_response(message, MessageType.PING)), self._logger) context.state = WaiterState() return elif message.author_node_id != context.node_id: wrap_exc(asyncio.async(context.send_response(message, MessageType.TOKEN_IS_HERE)), self._logger) context.send_broadcast(MessageType.TOKEN_IS_HERE) elif message.type == MessageType.WHERE_IS_TOKEN: wrap_exc(asyncio.async(context.send_response(message, MessageType.TOKEN_IS_HERE)), self._logger) elif message.type == MessageType.GENERATING_TOKEN: wrap_exc(asyncio.async(context.send_response(message, MessageType.TOKEN_IS_HERE)), self._logger) yield from context.send_broadcast(MessageType.TOKEN_IS_HERE)
def notify_state_changed(self, old_state, new_state): if self._debug_messenger is None: return message = ChangingStateBroadcast(self.node_id, old_state, new_state) logger.debug("Sending debug message: {}".format(message.__getstate__())) support.wrap_exc(asyncio.async(self._debug_messenger.send_message( serialize_message(message, task2.flow.messenger.ENCODING))), logger)
def _listen_messages(self): while True: address, data_bytes = yield from self.listen_message() message = deserialize_message(data_bytes, ENCODING) self._get_logger().debug('Deserialized message: {}...'.format(message.__getstate__())) if self._on_message is not None: # noinspection PyCallingNonCallable wrap_exc(asyncio.async(self._on_message(message, address)), self._get_logger()) self._message_queue.put_nowait(message)
def _taking_messages_loop(self): while True: takings = [] for listener in self._listeners.values(): takings.append(wrap_exc(asyncio.async(listener.take_message()), self._logger)) with auto_cancellation(takings): done, pending = yield from asyncio.wait(takings, return_when=concurrent.futures.FIRST_COMPLETED) for f in done: message = yield from f self._message_queue.put_nowait(message) self._logger.debug( 'Message {} putted. Queue size: {}.'.format(message.type, self._message_queue.qsize()))
def _on_message(self, message: Message, address): node_id = message.author_node_id if node_id in self._lost_nodes: self._lost_nodes.remove(node_id) self._logger.info('Heard about lost node again! (node_id={}) (so lost nodes: {})' .format(node_id, self._lost_nodes)) if node_id not in self.nodes: host = address[0] self._add_node(node_id, host) wrap_exc(asyncio.async(self.send_message(node_id, Message(MessageType.PING, self.node_id))), self._logger) elif address[0] != self.nodes[node_id]: self._logger.error('Unexpected state! My nodes: {}. {} != {} (node_id={})' .format(self.nodes, address[0], self.nodes[node_id], node_id)) if message.type == MessageType.TAKE_TOKEN: assert isinstance(message, TakeTokenMessage) for node_id, host in message.nodes.items(): if node_id not in self.nodes: self._add_node(node_id, host) else: if host != self.nodes[node_id]: self._logger.error('Unexpected state! My nodes: {}. Nodes in message: {}. {} != {} (node_id={})' .format(self.nodes, message.nodes, host, self.nodes[node_id], node_id))
def start(self): self._daemon = wrap_exc(asyncio.async(self._listen_messages()), self._get_logger())
def start(self): self._logger.info('Starting messengers...') for messenger in self._listeners.values(): messenger.start() self._logger.info('Messengers started!') self._daemon = wrap_exc(asyncio.async(self._taking_messages_loop()), self._logger)