Why is publishing on the same channel thread while consuming a problem?
Closed this issue · 4 comments
Hi,
I understand the solution of forking a new thread to do any complex consuming that involves further using the channel where we are consuming messages. What I don't fully understand is the reason why this is needed.
I understand it has to do with deadlocking the channel. In the case of publishing a new message, the operation might block if the channel is in flow mode. But why would this be a deadlock? Is it because the channel thread is blocked and thus it cannot receive the signal to be released from flow mode? Or is it a more subtle internal thing? Or is it just that other consumers from the same channel would get blocked, which is generally something you wouldn't want, but not necessarily a deadlock?
Thank you for your time!
(I have to admit that I don't really remember the details myself, so I did a short look into the source; hopefully my explanation is correct.)
The issue is basically a deadlock. The reason has to do with how the library handles incoming messages from the server.
Every channel has a single channelReceiver
loop that handles incoming messages; these can be both asynchronous messages from the server (e.g. messages from some AMQP exchange) as well as synchronous messages (responses to requests from the client).
It is vital that the channelReceiver
never becomes blocked, as it would be unable to process incoming synchronous messages, i.e. requests couldn't be processed anymore.
But since the consumeMsgs
callbacks are running inside channelReceiver
, if you perform a request, it will block (waiting for its response) the channelReceiver
which in turn will be unable to actually handle the response to that request.
Right. And the reason publishMsg is not in the list of safe operations is the waitLock of the writeAssembly
Cool, thanks!
All functions that internally use writeAssembly
should be safe, whereas the ones calling request
would be deadlocking. Therefore publishMsg
should also work (you can try it, if you want).
Having said that, I think the comment with the list of safe operations is probably wrong. For example, recoverMsgs
does internally use request
so it would deadlock. But looking at the commit history, it did use writeAssembly
in the past, so I probably just forgot to update the comment.
I'm also not sure why I didn't list publishMsg
in the comment.
Anyway, thank you for pointing this out. I'll update the comment soon.
Now that I think of it some more, you're right about the waitLock
. If flow-control is active, I think any channel operation might be problematic, since they all ultimately use writeAssembly'