ruby-amqp / bunny

Bunny is a popular, easy to use, mature Ruby client for RabbitMQ
Other
1.39k stars 303 forks source link

Queue auto deletion is not reflected in internal entity cache #579

Closed ionutzp closed 5 years ago

ionutzp commented 5 years ago

If a queue is auto deleted (a queue declared with auto_delete => true) it is still kept in the cache of ruby bunny Bunny::Channel#queues

This can cause an exception leading to the channel being closed(channel error: NOT_FOUND) when the queue gets deleted by the server by removing it's consumers, redeclared(queue is not recreated in the server) and then rebounded.

michaelklishin commented 5 years ago

I'm afraid Bunny cannot possibly know if a queue was autodeleted as it cannot track its consumers that may be coming from other connections.

michaelklishin commented 5 years ago

This is also the case for RabbitMQ Java client, for example: it will try to invalidate known "cache" entries that are auto-delete but it is only able to do so for queues and consumers managed on a single connection (it used to be a channel). There is no way a connection can know what's happening to consumers on other connections or in other processes.

Consider not sharing auto-delete queues or using passive declares where appropriate. No sharing means no queue "state" incoherencies.

ionutzp commented 5 years ago

Hi @michaelklishin i am using a single connection, and just deleting the single consumer of an auto delete queue. The server then deletes the queue but i couldn't seem to find anywhere in the code of ruby-bunny where the queue cache would be updated.

michaelklishin commented 5 years ago

As I explained above, Bunny cannot really get much insight into those events. It only has a chance to "correct" such discrepancies during connection recovery. RabbitMQ Java client is the most advanced in this area: it invalidates entries in its cache of known entities based on some of their attributes but only for operations that are performed on the same connection. In other words, if you cancel a consumer by closing a channel or using management tools, no client can discover that and update its cache.

AutorecoveringConnection and AutorecoveringChannel demonstrate the idea.

Bunny could do something similar and the cache can be connection-wide (it is per-channel). That still would not eliminate every scenario where the server decides to delete an entity for reasons that the client has no way to observe. Queue TTL is one obvious example.

michaelklishin commented 5 years ago

I'd consider a PR that adds an option that bypasses the cache for Bunny::Channel#queue and Bunny::Channel#exchange. Perhaps that would make it possible for you to sacrifice some efficiency but avoid running into operations on already deleted entities. So feel free to investigate this, it should be a fairly straightforward feature to add.

ionutzp commented 5 years ago

Ok I understand. I was under the impression that ruby-bunny also implements: it invalidates entries in its cache of known entities based on some of their attributes. As for if you cancel a consumer by closing a channel or using management tools, no client can discover that and update its cache. i would have no expectations there and my use case is explicitly cancelling a consumer. I will keep the PR in mind. Thanks for the information.