pika: pika throws ChannelWrongStateError('Channel is closed.') on publish

pika version: 1.1.0

As a result of interface link flapping a socket underneath pika’s connection to RabbitMQ became dead. Since this state transition has not been properly processed by client code any subsequent publish() to pika’s Channel then caused this:

  File "/opt/venv/lib/python3.6/site-packages/pika/adapters/blocking_connection.py", line 2210, in basic_publish
    mandatory=mandatory)
  File "/opt/venv/lib/python3.6/site-packages/pika/channel.py", line 421, in basic_publish
    self._raise_if_not_open()
  File "/opt/venv/lib/python3.6/site-packages/pika/channel.py", line 1389, in _raise_if_not_open
    raise exceptions.ChannelWrongStateError('Channel is closed.')
pika.exceptions.ChannelWrongStateError: Channel is closed.

As a result: a code like

try:
    self.channel.basic_publish(*a, **k)
except (exceptions.ConnectionClosed, exceptions.ChannelClosed) as error:
    log.debug('Try to reconnect in 5 seconds')
    time.sleep(5)
    self.reconnect()

would fail.

This behaviour was implemented at https://github.com/pika/pika/commit/761ef5cf8e484fe8d52909e767ceef69afc82d3a

But I disagree in total with the approach since it brakes the whole typed exception support of python itself. Typed exceptions are supported for the user of code can just quickly match the error yielded by runtime despite what’s the actual reason. The commit mentioned brakes this and offers code users to revert to strings patterns matching. Instead of raising the same exception in cases:

  • channel is in opening state but is not ready to operate
  • channel is [already] closed

one should provide a special type of an exception for each of the cases if the error recovery is supposed to differ, IMO.

For these two cases error recovery approaches obviously to me differ in total. For the channel in opening state it’s wait a little then try again (but don’t reconnect since there’s no reason for it); for the channel is in closed state it could be recover via reconnect. Right now the code user differs what approach to use only with the Exception.args parsing.

About this issue

  • Original URL
  • State: open
  • Created 5 years ago
  • Comments: 16 (7 by maintainers)

Commits related to this issue

Most upvoted comments

Is there any update here? In the connection pool with a heartbeat, connections are getting dropped as well.

@lukebakken hello … this the lgs i got from RabbitMQ . is it ok or i miss some things?

2023-10-23 16:12:10.750047+00:00 [info] <0.20042.3> connection <0.20042.3> ([::1]:42330 -> [::1]:5672): user 'ghouse' authenticated and granted access to vhost '/'
2023-10-23 16:12:10.751565+00:00 [info] <0.20045.3> connection <0.20045.3> ([::1]:42334 -> [::1]:5672): user 'ghouse' authenticated and granted access to vhost '/'
2023-10-23 16:12:10.816502+00:00 [info] <0.20068.3> accepting AMQP connection <0.20068.3> ([::1]:42348 -> [::1]:5672)
2023-10-23 16:12:10.818977+00:00 [info] <0.20068.3> connection <0.20068.3> ([::1]:42348 -> [::1]:5672): user 'ghouse' authenticated and granted access to vhost '/'
2023-10-23 16:15:10.752762+00:00 [erro] <0.20042.3> closing AMQP connection <0.20042.3> ([::1]:42330 -> [::1]:5672):
2023-10-23 16:15:10.752762+00:00 [erro] <0.20042.3> missed heartbeats from client, timeout: 60s
2023-10-23 16:15:10.753537+00:00 [erro] <0.20045.3> closing AMQP connection <0.20045.3> ([::1]:42334 -> [::1]:5672):
2023-10-23 16:15:10.753537+00:00 [erro] <0.20045.3> missed heartbeats from client, timeout: 60s
2023-10-23 16:15:10.821715+00:00 [erro] <0.20068.3> closing AMQP connection <0.20068.3> ([::1]:42348 -> [::1]:5672):
2023-10-23 16:15:10.821715+00:00 [erro] <0.20068.3> missed heartbeats from client, timeout: 60s

there was no network issue. and after few tries rabbitmq works fine like and then it again gives me channel closed or pika.exceptions.StreamLostError: Stream connection lost: ConnectionResetError(104, ‘Connection reset by peer’)

Hi, I had the same error, but not the exact situation. First I had basic_publish that didn’t handle a StreamLostError. Then, on the same channel another basic_publish raised a ChannelWrongStateError with the same message.

I think it’s confusing, since that the documentation says it will raise UnroutableError and NackError only.