Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

106 строки
4.1KB

  1. import asyncio
  2. import pickle
  3. from socketio.asyncio_pubsub_manager import AsyncPubSubManager
  4. try:
  5. import aio_pika
  6. except ImportError:
  7. aio_pika = None
  8. class AsyncAioPikaManager(AsyncPubSubManager): # pragma: no cover
  9. """Client manager that uses aio_pika for inter-process messaging under
  10. asyncio.
  11. This class implements a client manager backend for event sharing across
  12. multiple processes, using RabbitMQ
  13. To use a aio_pika backend, initialize the :class:`Server` instance as
  14. follows::
  15. url = 'amqp://user:password@hostname:port//'
  16. server = socketio.Server(client_manager=socketio.AsyncAioPikaManager(
  17. url))
  18. :param url: The connection URL for the backend messaging queue. Example
  19. connection URLs are ``'amqp://guest:guest@localhost:5672//'``
  20. for RabbitMQ.
  21. :param channel: The channel name on which the server sends and receives
  22. notifications. Must be the same in all the servers.
  23. With this manager, the channel name is the exchange name
  24. in rabbitmq
  25. :param write_only: If set ot ``True``, only initialize to emit events. The
  26. default of ``False`` initializes the class for emitting
  27. and receiving.
  28. """
  29. name = 'asyncaiopika'
  30. def __init__(self, url='amqp://guest:guest@localhost:5672//',
  31. channel='socketio', write_only=False, logger=None):
  32. if aio_pika is None:
  33. raise RuntimeError('aio_pika package is not installed '
  34. '(Run "pip install aio_pika" in your '
  35. 'virtualenv).')
  36. self.url = url
  37. self.listener_connection = None
  38. self.listener_channel = None
  39. self.listener_queue = None
  40. super().__init__(channel=channel, write_only=write_only, logger=logger)
  41. async def _connection(self):
  42. return await aio_pika.connect_robust(self.url)
  43. async def _channel(self, connection):
  44. return await connection.channel()
  45. async def _exchange(self, channel):
  46. return await channel.declare_exchange(self.channel,
  47. aio_pika.ExchangeType.FANOUT)
  48. async def _queue(self, channel, exchange):
  49. queue = await channel.declare_queue(durable=False,
  50. arguments={'x-expires': 300000})
  51. await queue.bind(exchange)
  52. return queue
  53. async def _publish(self, data):
  54. connection = await self._connection()
  55. channel = await self._channel(connection)
  56. exchange = await self._exchange(channel)
  57. await exchange.publish(
  58. aio_pika.Message(body=pickle.dumps(data),
  59. delivery_mode=aio_pika.DeliveryMode.PERSISTENT),
  60. routing_key='*'
  61. )
  62. async def _listen(self):
  63. retry_sleep = 1
  64. while True:
  65. try:
  66. if self.listener_connection is None:
  67. self.listener_connection = await self._connection()
  68. self.listener_channel = await self._channel(
  69. self.listener_connection
  70. )
  71. await self.listener_channel.set_qos(prefetch_count=1)
  72. exchange = await self._exchange(self.listener_channel)
  73. self.listener_queue = await self._queue(
  74. self.listener_channel, exchange
  75. )
  76. async with self.listener_queue.iterator() as queue_iter:
  77. async for message in queue_iter:
  78. with message.process():
  79. return pickle.loads(message.body)
  80. except Exception:
  81. self._get_logger().error('Cannot receive from rabbitmq... '
  82. 'retrying in '
  83. '{} secs'.format(retry_sleep))
  84. self.listener_connection = None
  85. await asyncio.sleep(retry_sleep)
  86. retry_sleep *= 2
  87. if retry_sleep > 60:
  88. retry_sleep = 60