Polyconseil / aioamqp

AMQP implementation using asyncio
Other
280 stars 88 forks source link

Wrong conversion for message-ttl #180

Closed Jacobh2 closed 5 years ago

Jacobh2 commented 5 years ago

Declaring a queue, which I know already exist, gives a 406 Precondition Failed error:

aioamqp.exceptions.ChannelClosed: (406, "PRECONDITION_FAILED - inequivalent arg 'x-message-ttl' for queue 'text' in vhost '/': received '-1875767295' but current is '2419200000'")

Seems like when I declare the queue (2419200000 = 4 weeks in milliseconds):

await channel.queue_declare(
        queue_name=QUEUE, durable=True, arguments={
            'x-message-ttl': 2419200000,
            'x-max-priority': 2
        }
    )

it is somehow interpreted as -1875767295. I found what I think is the location where it parses the arguments values, which is shown here.

My best guess is that it is parsing the value as a signed 32 bit int, when it should be a 64 bit number, but I'm really not sure since the method used in the linked code is using write_long.

Any ideas on what is wrong?

dzen commented 5 years ago

Hello,

from the doc: The argument can be of AMQP type short-short-int, short-int, long-int, or long-long-int.

we're actualy writing longs from int and we do not support long-long-int from now. The code should probably guess which type of int it should write on the wire.

Jacobh2 commented 5 years ago

Ok, so the problem is that the code right now writes it as a long-int and aioamqp does not support long-long-int?

Is there any plans on supporting this in a near future?

Thank you for the clarification!

dzen commented 5 years ago

The code should probably be smart enough to write the correct "type" on the wire depending on the int length I would love to create a PR for this, but I'm not sure to have the time for. Another bet is to use directly https://github.com/gmr/pamqp to encode and decode frames and params.

Jacobh2 commented 5 years ago

Ok! 👍 I'll see if I find the time to create a PR for this.

I'm thinking something like

if value.bit_length() >= 32:
    self.write_long_long(value)
else:
    self.write_long(value)

But I'll have to read up on the protocol in order to know if the self.payload.write(b'I') needs to be changed since it is no longer a long, but a long-long!

dzen commented 5 years ago

well, beware, bit_length is a python2 only method ;)

Jacobh2 commented 5 years ago

No? I have used it in both 3.5 and 3.7.

Also, it is listed here

dzen commented 5 years ago

Just released a minute ago