0

I have a queue in RabbitMQ. I can't configurate this queue, I have to consume messages from it. Publisher don't use Masstransit for publishing. I am using Masstransit to consume messages from the queue.

When I am trying to configurate connection to the queue, I am receiving this error:

The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text='PRECONDITION_FAILED - inequivalent arg 'type' for exchange 'my_queue' in vhost 'my_vhost': received 'fanout' but current is 'direct'', classId=40, methodId=10

My configuration looks like:

Bus.Factory.CreateUsingRabbitMq(cfg =>
{
    cfg.Host("127.0.0.1", "my_virtual_host", credintials =>
    {
        credintials.Username("myuser");
        credintials.Password("mypassword");
    });

    cfg.ReceiveEndpoint("my_queue", e =>
    {

        e.UseRawJsonSerializer();
        e.Consumer(() => _messageConsumer);
    });
}).Start();

The queue has configuration Durable = true and that's it, nothing special.

When I am trying to connect to the queue via RabbitMQ.Client, it connects without problems. Consuming works well too.

How can I solve the problem?

Phil
  • 82
  • 8

2 Answers2

1

The issue is the my_queue exchange already exists with a direct exchange type. By default, MassTransit will create this exchange as a fanout exchange. Direct exchanges are used for routing messages via routing key. For an example of using direct exchanges with MassTransit, check out the direct sample.

You can see the broker topology configured by MassTransit for RabbitMQ.

Chris Patterson
  • 28,659
  • 3
  • 47
  • 59
  • I am using .NET5 and `cfg.ConfigureMessageTopology();` not found extension method. In `cfg.ReceiveEndpoint` I have added `endpoint.ConfigureConsumeTopology = false;` and `endpoint.Bind<>` and `endpoint.Handler<>`. But I still have the same error. It seems like Masstransit doesn't see the existing queue. If I set another queue name like `cfg.ReceiveEndpoint("direct.client.my_queue", endpoint =>` it creates queue in RabbitMQ. But I need to connect to the existing queue with name `my_queue`. Is it possible to not create, just connect to the existing queue (created not by Masstransit publisher)?:) – Phil Feb 16 '21 at 21:38
  • 1
    As I stated in the answer, MassTransit uses a matching exchange/queue pair with the same name, and the error reported by RabbitMQ was that the exchange type did not match the expected type (fanout, was direct). Any additional configuration would have to be on the receive endpoint – you _might_ be able to specify the ExchangeType there, but it's outside of what MassTransit expects. – Chris Patterson Feb 16 '21 at 22:39
0

I solve my problem. Connection to Masstransit looks like:

private async Task InitMasstransitBusAsync(CancellationToken cancellationToken)
{
    await Bus.Factory.CreateUsingRabbitMq(cfg =>
    {
        cfg.Host(new Uri(_rabbitMqConfig.HostName), credintials =>
        {
            credintials.Username(_rabbitMqConfig.UserName);
            credintials.Password(_rabbitMqConfig.Password);

        });
        cfg.ReceiveEndpoint(_rabbitMqConfig.QueueName, e =>
        {
            e.PrefetchCount = 20;
            e.ExchangeType = "direct";
            e.ConfigureConsumeTopology = false;
            e.AddMessageDeserializer(new ContentType("text/plain"),
                () => new CustomMessageDeserializer("text/plain"));
            e.Consumer(() => _messageConsumer);
        });
    }).StartAsync(cancellationToken);
}

CustomMessageDeserializer:

    public class CustomMessageDeserializer : IMessageDeserializer
    {
        private readonly string _contentType;
        private readonly JsonSerializer _serializer = JsonSerializer.Create();

        public CustomMessageDeserializer(string contentType)
        {
            _contentType = contentType;
        }

        public ContentType ContentType => new(_contentType);

        public ConsumeContext Deserialize(ReceiveContext receiveContext)
        {
            try
            {
                var messageEncoding = GetMessageEncoding(receiveContext);
                using var body = receiveContext.GetBodyStream();
                using var reader = new StreamReader(body, messageEncoding, false, 1024, true);
                using var jsonReader = new JsonTextReader(reader);
                var messageToken = _serializer.Deserialize<JToken>(jsonReader);
                
                return new RawJsonConsumeContext(_serializer, receiveContext, messageToken);
            }
            catch (JsonSerializationException ex)
            {
                throw new SerializationException("A JSON serialization exception occurred while deserializing the message", ex);
            }
            catch (SerializationException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new SerializationException("An exception occurred while deserializing the message", ex);
            }
        }

        public void Probe(ProbeContext context) { }

        public static Encoding GetMessageEncoding(ReceiveContext receiveContext)
        {
            var contentEncoding = receiveContext.TransportHeaders.Get("Content-Encoding", default(string));
            return string.IsNullOrWhiteSpace(contentEncoding) ? Encoding.UTF8 : Encoding.GetEncoding(contentEncoding);
        }

    }
Phil
  • 82
  • 8