Setting x-message-ttl - signedint versus long

1,103 views
Skip to first unread message

Peter Hicks

unread,
Oct 11, 2011, 4:44:01 AM10/11/11
to Ruby AMQP ecosystem
All,

I have a queue with a TTL of 3,600,000, and I'm trying to bind to it
to receive data. All I get is the error:

PRECONDITION_FAILED - inequivalent arg 'x-message-ttl' for queue
'tdnet.stage.trust' in vhost 'tdnet': received the value '3600000' of
type 'signedint' but current is the value '3600000' of type 'long'

I can't see anywhere where I set the value as signedint or long - my
code is as follows:

channel = AMQP::Channel.new(connection)
queue = channel.queue("trust", :durable => true, :arguments => { 'x-
message-ttl' => 3600000 })
exchange = channel.fanout("tdnet.exch.trust", :durable => true)

If I recreate the queue on the RabbitMQ server without a TTL value,
and remove the :arguments parameter, I can connect successfully.

Can anyone guide me in the right direction?

Kind regards,


Peter

Michael Klishin

unread,
Oct 12, 2011, 12:35:59 PM10/12/11
to ruby...@googlegroups.com
Le 11/ott/2011 à 12:44, Peter Hicks a écrit :

> If I recreate the queue on the RabbitMQ server without a TTL value,
> and remove the :arguments parameter, I can connect successfully.
>
> Can anyone guide me in the right direction?

I never tried values this large but all numbers in attribute tables (like :arguments) are serialized as unsigned 32-bit integers. I need to take a look at the spec to see if this is the correct data type and what RabbitMQ Java client uses.

MK

http://github.com/michaelklishin
http://twitter.com/michaelklishin

Michael Klishin

unread,
Oct 12, 2011, 12:42:06 PM10/12/11
to ruby...@googlegroups.com
Le 12/ott/2011 à 20:35, Michael Klishin a écrit :

> I never tried values this large but all numbers in attribute tables (like :arguments) are serialized as unsigned 32-bit integers. I need to take a look at the spec to see if this is the correct data type and what RabbitMQ Java client uses.

Ok, so RabbitMQ Java client serializes all integers as long values. We'll have to make amq-protocol do the same. I hope to look into this later today.

Peter Hicks

unread,
Oct 12, 2011, 12:39:27 PM10/12/11
to ruby...@googlegroups.com

Correct me if I'm wrong, bit these values are in milliseconds aren't they?

P

Michael Klishin

unread,
Oct 12, 2011, 1:05:28 PM10/12/11
to ruby...@googlegroups.com

Le 12/ott/2011 à 20:39, Peter Hicks a écrit :

> Correct me if I'm wrong, bit these values are in milliseconds aren't they?

They are. But because this is an extension to AMQP 0.9.1 spec, attribute table values that are Ruby integers are serialized as 32-bit ints and not longs. RabbitMQ extensions page kinda tries to hint at this but is not specific and that part is easy to overlook:

«The value of the x-message-ttl argument must be an integer, greater than zero, describing the TTL period in milliseconds. Thus a value of 1000 means that a message added to the queue will live in the queue for 1 second or until it is delivered to a consumer. The argument can be of AMQP type short-short-int, short-int, long-int, or long-long-int.»

In the RabbitMQ source I see that integers are written as longs but then at the very end of the serialization DataOutputStream#writeInt is used to white these supposedly long values. Looks like there is no consensus on what table values that are integers should be treated as. Changing this to be long will mean "older" clients won't be able to deserialize data properly.

Stefan Kaes

unread,
Oct 12, 2011, 1:25:17 PM10/12/11
to ruby...@googlegroups.com
Looking at the description I would say that clients must be able to deal with any integer type and RabbitMQ must be able to deal with any inter type.

I would say this is a rabbitmq bug, isn't it?

Michael Klishin

unread,
Oct 12, 2011, 1:32:22 PM10/12/11
to ruby...@googlegroups.com

Le 12/ott/2011 à 21:25, Stefan Kaes a écrit :

> Looking at the description I would say that clients must be able to deal with any integer type and RabbitMQ must be able to deal with any inter type.

amq-protocol serializes it as a 32-bit unsigned integer while provided value falls into the longs range. If you take a look at the RabbitMQ Java client source, it serializes Java integers and longs as longs, probably to make extensions like message TTL work with realistic values.

I am trying to clarify this with RabbitMQ team members.

>
> I would say this is a rabbitmq bug, isn't it?

If you ask me, it is not. It is a limitation of amq-protocol that we did not foresee because this part of behavior was not really specified in the core spec and depends heavily on what various extensions use. I am almost done lifting it up.

Michael Klishin

unread,
Oct 12, 2011, 2:12:28 PM10/12/11
to ruby...@googlegroups.com

Le 11/ott/2011 à 12:44, Peter Hicks a écrit :

> PRECONDITION_FAILED - inequivalent arg 'x-message-ttl' for queue
> 'tdnet.stage.trust' in vhost 'tdnet': received the value '3600000' of
> type 'signedint' but current is the value '3600000' of type 'long'

Peter,

I've implemented serialization of integer :arguments values as longs [1] but it causes 2 failures in the amqp gem test suite. I need more time to investigate this. I recommend that you report this finding to the rabbitmq-discuss mailing list. If it makes sense for clients

In your case 3600 * 1000 is lower than max integer value and max value seems to support values up to several hundreds of hours, so amqp gem serialization in this case is very reasonable.

That said, if I can get serialization as longs working without test suite failures, I am fine with supporting that if it helps as a workaround.


1. https://github.com/ruby-amqp/amq-protocol/commit/61da5c9a6f9884c234492034d9772715e3034537

Michael Klishin

unread,
Oct 12, 2011, 2:58:08 PM10/12/11
to ruby...@googlegroups.com
Le 12/ott/2011 à 22:12, Michael Klishin a écrit :

>> PRECONDITION_FAILED - inequivalent arg 'x-message-ttl' for queue
>> 'tdnet.stage.trust' in vhost 'tdnet': received the value '3600000' of
>> type 'signedint' but current is the value '3600000' of type 'long'
>
> Peter,
>

> …


>
> In your case 3600 * 1000 is lower than max integer value and max value seems to support values up to several hundreds of hours, so amqp gem serialization in this case is very reasonable.
>

Peter,

A follow-up to my own reply. After reading the error message and asking a RabbitMQ team member, my impression of what may be going on is this:

* You have another app that uses Java client and declares the same exchange.
* Then your app that uses amqp gem redeclares it.
* Even though values are equal in practices, types are different and thus RabbitMQ rejects this redeclaration.

While this means we have to use 64-bit integers in the amqp gem, there is a workaround you can use right now: make your Ruby application declare that queue with :passive => true. In this case if the queue exists, the result will be successful. If not, a channel [AMQP] exception will be raised.

I will try to investigate why we have 2 failures in amqp gem test suite after switching to longs and release a new amq-protocol version once we are done.

Thank you for finding this compatibility edge case.

Reply all
Reply to author
Forward
0 new messages