ruby-amqp/bunny — pull request #44 by qpingu (2012-03-13 21:57:11+00:00)
Title: Fix a race condition with subscribe and timeouts

The race condition exists when Bunny cancels a subscribe, either because of a timeout or cancellator write, while it is in the process of receiving a message.

The first commit deals with the fact that the timeout can fire during the parsing of the message. This causes all parsing to suddenly halt, leaving the buffer in a completely broken state (that causes future actions to hang). The change introduces a waiting stage (read_ready?), where we use IO.select and wait for either the buffer, the cancellator, or the timeout to change first.

The second commit deals with the handling of the message received as we try to unsubscribe. Rather than throw an exception and possibly lose this message (if ack=false), the code tries to process this last message with the consideration that a CancelOk method is scattered somewhere in the buffer. This makes an important method more complex, but still follows the same logic for the normal case.

In theory, there is still a small chance that the CancelOk reaches the client before the actual message does, in which case the unparsed message will cause an exception, but that's almost completely unavoidable unless you have a proper, asynchronous library. It's also a good reason to use ack...