Skip to content

RMQ gateways declare transient non-exclusive queues, which RabbitMQ 4.3 blocks by default #4355

Description

@iancooper

Summary

Both RMQ gateways (RMQ.Sync and RMQ.Async) declare their queues as transient, non-exclusive, non-auto-delete. RabbitMQ 4.3 blocks that combination by default, so with the out-of-the-box subscription configuration a Brighter consumer cannot connect at all on 4.3.

CI pins 4.2, so this is invisible today.

Measured

Observed against stock rabbitmq:4-management (RabbitMQ 4.3.5). Every RMQ.Sync gateway test fails during Receive:

Paramore.Brighter.ChannelFailureException : Error connecting to RabbitMQ, see inner exception for details
---- RabbitMQ.Client.Exceptions.OperationInterruptedException : The AMQP operation was interrupted:
     AMQP close-reason, initiated by Peer, code=541,
     text='INTERNAL_ERROR - Feature `transient_nonexcl_queues` is deprecated.
     By default, this feature is not permitted anymore.
     The feature will be removed from a future major RabbitMQ version, regardless of the
     configuration; actual version to be determined.'
     classId=50, methodId=10

Stack reaches the broker through:

RmqMessageConsumer.CreateQueue()   -> Channel.QueueDeclare(...)
RmqMessageConsumer.EnsureChannel()
RmqMessageConsumer.Receive(TimeSpan?)

Cause

durable: false, exclusive: false, autoDelete: false is exactly the deprecated transient_nonexcl_queues combination.

  • src/Paramore.Brighter.MessagingGateway.RMQ.Sync/RmqMessageConsumer.cs:460
    Channel.QueueDeclare(_queueName.Value, _isDurable, false, false, SetQueueArguments());
    //NOTE: hasDlq cannot be true if _deadLetterQueuename is null
    if (_hasDlq) Channel.QueueDeclare(_deadLetterQueueName!.Value, _isDurable, false, false, new Dictionary<string, object>());
  • src/Paramore.Brighter.MessagingGateway.RMQ.Async/RmqMessageConsumer.cs:541 and :546 do the same asynchronously.

_isDurable comes from the subscription, and false is the default on both gateways — RmqSubscription.cs:106 and :165 (Sync), :113 and :176 (Async). So the failure is the default path, not an unusual configuration. Setting isDurable: true on the subscription avoids it.

Note the dead-letter queue declaration inherits _isDurable too, so a durable subscription fixes both declarations together.

Impact

  • On RabbitMQ 4.3 and later, any consumer that does not explicitly opt into isDurable: true fails to start.
  • The deprecation notice says the feature "will be removed from a future major RabbitMQ version, regardless of the configuration" — so permitting it via broker config is a stopgap, not a fix.

Suggested direction

Decide what Brighter should declare when isDurable: false. The options that keep working on 4.3+ are a durable queue, or an auto-delete and/or exclusive queue where the transient lifetime is actually what the caller wanted. Worth settling deliberately, since it changes queue lifetime semantics for existing users.

How it was found

Incidentally, while verifying the migration of the RMQ CI images off the brightercommand/rabbitmq:*-management-delay plugin builds onto stock images (#4240 / #4297). The machine happened to have a 4.3.5 broker on localhost:5672; the CI images are 4.2 and 3.13 and are unaffected.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions