Module server.protocol.rabbitmq
RabbitMQ wire protocol: consumes from a queue and publishes via MessageQueueService.
Classes
class RabbitMQProtocol (queue: asyncio.queues.Queue, server_context: ServerContext, session: int)-
Expand source code
class RabbitMQProtocol(Protocol): """ Protocol implementation that receives messages from a RabbitMQ queue and sends messages by publishing via MessageQueueService. All messages are assumed to be dictionary objects. """ def __init__( self, queue: asyncio.Queue, server_context: "ServerContext", session: int, ): """ Wrap a queue providing messages and message queue service. # Parameters - queue: queue providing incoming messages - message_queue_service: MessageQueueService instance used for publishing messages - session: session id for the protocol """ self.queue = queue self.server_context = server_context self.exchange_name = config.OUTBOUND_EXCHANGE_NAME self.session = session self._pending: set[asyncio.Task] = set() self._closed = False @staticmethod def encode_message(message: dict) -> bytes: return json_encoder.encode(message).encode() @staticmethod def decode_message(data: bytes) -> dict: return json.loads(data) def is_connected(self) -> bool: if self._closed: return False return True async def read_message(self) -> dict: if not self.is_connected(): raise DisconnectedError("RabbitMQ protocol is not connected!") item = await self.queue.get() if item is _SENTINEL or not self.is_connected(): raise DisconnectedError("RabbitMQ connection closed") return item def write_message( self, message: dict, ) -> None: metrics.sent_messages.labels(self.__class__.__name__).inc() if not self.is_connected(): raise DisconnectedError("Protocol is not connected!") if self.server_context is None: raise DisconnectedError("No message queue service configured for publishing!") task = asyncio.create_task( self.server_context.publish( exchange_name=config.OUTBOUND_EXCHANGE_NAME, routing="", payload=self._wrap_message_with_session(message), delivery_mode=DeliveryMode.NOT_PERSISTENT, ) ) self._pending.add(task) task.add_done_callback(self._pending.discard) def write_messages( self, messages: list[dict], ) -> None: metrics.sent_messages.labels(self.__class__.__name__).inc() if not self.is_connected(): raise DisconnectedError("Protocol is not connected!") if self.server_context is None: raise DisconnectedError("No message queue service configured for publishing!") task = asyncio.create_task( self.server_context.publish_many( exchange_name=config.OUTBOUND_EXCHANGE_NAME, routing="", payloads=[self._wrap_message_with_session(message) for message in messages], delivery_mode=DeliveryMode.NOT_PERSISTENT, ) ) self._pending.add(task) task.add_done_callback(self._pending.discard) def write_raw(self, data: bytes) -> None: payload = self.decode_message(data) self.write_message(payload) def _wrap_message_with_session(self, payload: dict) -> dict: return {"target": {"@type": "session", "session_id": self.session}, "message": payload} async def drain(self) -> None: if not self._pending: return try: await asyncio.gather(*self._pending) except Exception as e: await self.close() raise DisconnectedError("Protocol connection lost!") from e def abort(self) -> None: self._closed = True for task in self._pending: task.cancel() self.queue.put_nowait(_SENTINEL) async def close(self) -> None: self._closed = True if ( self.queue is not None ): self.queue.put_nowait(_SENTINEL)Protocol implementation that receives messages from a RabbitMQ queue and sends messages by publishing via MessageQueueService. All messages are assumed to be dictionary objects.
Wrap a queue providing messages and message queue service.
Parameters
- queue: queue providing incoming messages
- message_queue_service: MessageQueueService instance used for publishing messages
- session: session id for the protocol
Ancestors
Methods
def abort(self) ‑> None-
Expand source code
def abort(self) -> None: self._closed = True for task in self._pending: task.cancel() self.queue.put_nowait(_SENTINEL)
Inherited members