mosquito / aio-pika

AMQP 0.9 client designed for asyncio and humans.
https://aio-pika.readthedocs.org/
Apache License 2.0
1.18k stars 186 forks source link

Generated anonymous queue name may conflict if random seed is fixed (with connect_robust) #485

Closed manfred-exz closed 1 year ago

manfred-exz commented 1 year ago

Issue

Because RobustQueue._get_random_queue_name() uses python's global random generator, it always produce the same anonymous queue name if user has a fixed random seed. Which is certainly not desired.

And a library should not restrict users to use the global random generator, so I think this is a bug.

How I encounter this issue

I declared some callback queue to be anonymous and exclusive. If the same queue name is already declared, I get this error message.

aiormq.exceptions.ChannelLockedResource: RESOURCE_LOCKED - cannot obtain exclusive access to locked queue 'amq_0xe5712ff7671b26d9377140c8cfbffcbb' in vhost '/'. 
It could be originally declared on another connection or the exclusive property value does not match that of the original declaration.

Reproduce

You will always get same queue name

import asyncio
import random

import aio_pika

async def main():
    random.seed(0)
    conn = await aio_pika.connect_robust('amqp://localhost')
    channel = await conn.channel()
    queue = await channel.declare_queue()
    print(queue.name)

if __name__ == '__main__':
    asyncio.run(main())

Fix

Use a standalone random generator should fix this problem.

# aio_pika/robust_queue.py
class RobustQueue(Queue, AbstractRobustQueue):
    __slots__ = ("_consumers", "_bindings")

    _consumers: Dict[ConsumerTag, Dict[str, Any]]
    _bindings: Dict[Tuple[Union[AbstractExchange, str], str], Dict[str, Any]]

    _rnd_gen: random.Random = random.Random()

    @classmethod
    def _get_random_queue_name(cls) -> str:
        rnd = cls._rnd_gen.getrandbits(128)
        return "amq_%s" % hex(rnd).lower()