0

(follow up to Why does my MassTransit Fault Consumer not get called?)

I am using MassTransit 7.1.4.0 together with RabbitMQ 3.8.7.

After I make changes to the C# code I get (detailed error message below)

Unhandled exception. MassTransit.RabbitMqTransport.RabbitMqConnectionException: ReceiveTransport faulted: localhost:5672/

The changes to the code

  • Add the keyword public to a class definition

I tried

  1. Undoing code changes.
  2. Rename EndpointName
  3. Deleting queues and exchanges in RabbitMQ admin http://localhost:15672/
  4. reboot
  5. stop start RabbitMq Windows service

None of these attempts work.

Application Below is the C# application

using System;
using System.Threading.Tasks;
using GreenPipes;
using MassTransit;
using MassTransit.ConsumeConfigurators;
using MassTransit.Definition;
using Microsoft.Extensions.DependencyInjection;

namespace FaultConsumer
{
  class Program
  {
    static async Task Main(string[] args)
    {
      Console.WriteLine("Hello Fault Consumer!");

      var services = new ServiceCollection();

      services.AddMassTransit(x =>
      {

        x.AddConsumer<MyConsumer>(typeof(MyConsumerDefinition));
        //x.AddConsumer<MyFaultConsumer>();//typeof(MyFaultConsumerDefinition));
        x.SetKebabCaseEndpointNameFormatter();
        x.UsingRabbitMq((context, cfg) =>
        {
          cfg.Host("rabbitmq://localhost");
          cfg.ConfigureEndpoints(context);
        });

      });


      var serviceProvider = services.BuildServiceProvider();
      var bus = serviceProvider.GetRequiredService<IBusControl>();

      await bus.StartAsync();

      await bus.Publish(new SubmitOrder() { DateTimeStamp = DateTime.Now });
      Console.WriteLine("Press any key to exit");
      await Task.Run(() => Console.ReadKey());

      await bus.StopAsync();

    }
  }


  //CHANGE I changed this to public (and back)
  class SubmitOrder
  {
    public DateTime DateTimeStamp { get; set; }
  }

  //CHANGE I changed this to public (and back)
  class MyConsumer : IConsumer<SubmitOrder>
  {
    public async Task Consume(ConsumeContext<SubmitOrder> context)
    {
      Console.WriteLine($"Attempting to consume {context.GetRetryCount()} {context.GetRetryAttempt()}");
      throw new Exception(context.GetRetryCount().ToString());
    }
  }

  //CHANGE I changed this to public (and back)
  class MyConsumerDefinition : ConsumerDefinition<MyConsumer>
  {
    public MyConsumerDefinition()
    {
      EndpointName = "order-service-202102081403";

      ConcurrentMessageLimit = 8;
    }

    protected override void ConfigureConsumer(IReceiveEndpointConfigurator endpointConfigurator,
          IConsumerConfigurator<MyConsumer> consumerConfigurator)
    {
      endpointConfigurator.UseMessageRetry(r => r.Intervals(100, 200, 500, 800, 1000));
      //endpointConfigurator.UseMessageRetry(r => r.Immediate(5));

      endpointConfigurator.UseInMemoryOutbox();
    }
  }

  //CHANGE I changed this to public (and back)
  class MyFaultConsumer : IConsumer<Fault<SubmitOrder>>
  {
    public async Task Consume(ConsumeContext<Fault<SubmitOrder>> context)
    {
      Console.WriteLine("Fault");
      await Task.CompletedTask;
    }

  }

  //CHANGE I changed this to public (and back)
  //   class MyFaultConsumerDefinition : ConsumerDefinition<MyFaultConsumer>
  //   {
  //     public MyFaultConsumerDefinition()
  //     {
  //       // override the default endpoint name
  //       EndpointName = "order-service-faults-202102081342";

  //       // limit the number of messages consumed concurrently
  //       // this applies to the consumer only, not the endpoint
  //       ConcurrentMessageLimit = 8;
  //     }

  //     protected override void ConfigureConsumer(IReceiveEndpointConfigurator endpointConfigurator,
  //           IConsumerConfigurator<MyFaultConsumer> consumerConfigurator)
  //     {
  //       // configure message retry with millisecond intervals
  //       endpointConfigurator.UseMessageRetry(r => r.Intervals(100, 200, 500, 800, 1000));

  //       // use the outbox to prevent duplicate events from being published
  //       endpointConfigurator.UseInMemoryOutbox();
  //     }
  //   }
}

Detailed Error Message

Unhandled exception. MassTransit.RabbitMqTransport.RabbitMqConnectionException: ReceiveTransport faulted: localhost:5672/
 ---> RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text='PRECONDITION_FAILED - inequivalent arg 'durable' 
for exchange 'FaultConsumer:SubmitOrder' in vhost '/': received 'false' but current is 'true'', classId=40, methodId=10
   at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply(TimeSpan timeout)
   at RabbitMQ.Client.Impl.ModelBase.ModelRpc(MethodBase method, ContentHeaderBase header, Byte[] body)
   at RabbitMQ.Client.Framing.Impl.Model._Private_ExchangeDeclare(String exchange, String type, Boolean passive, Boolean durable, Boolean autoDelete, Boolean internal, Boolean nowait, IDictionary`2 arguments)
   at RabbitMQ.Client.Impl.ModelBase.ExchangeDeclare(String exchange, String type, Boolean durable, Boolean autoDelete, IDictionary`2 arguments)
   at MassTransit.RabbitMqTransport.Contexts.RabbitMqModelContext.<>c__DisplayClass16_0.<MassTransit.RabbitMqTransport.ModelContext.ExchangeDeclare>b__0()
   at MassTransit.Util.ChannelExecutor.<>c__DisplayClass10_0.<Run>g__RunMethod|0()
   at MassTransit.Util.ChannelExecutor.<>c__DisplayClass10_0.<Run>b__1()
   at MassTransit.Util.ChannelExecutor.SynchronousFuture`1.Run()
--- End of stack trace from previous location ---
   at MassTransit.Util.ChannelExecutor.Run[T](Func`1 method, CancellationToken cancellationToken)
   at MassTransit.RabbitMqTransport.Pipeline.ConfigureTopologyFilter`1.ConfigureTopology(ModelContext context)
   at MassTransit.RabbitMqTransport.Pipeline.ConfigureTopologyFilter`1.<>c__DisplayClass3_0.<<GreenPipes-IFilter<MassTransit-RabbitMqTransport-ModelContext>-Send>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at GreenPipes.PipeExtensions.OneTimeSetup[T](PipeContext context, Func`2 setupMethod, PayloadFactory`1 payloadFactory)
   at MassTransit.RabbitMqTransport.Pipeline.ConfigureTopologyFilter`1.GreenPipes.IFilter<MassTransit.RabbitMqTransport.ModelContext>.Send(ModelContext context, IPipe`1 next)
   at GreenPipes.Agents.PipeContextSupervisor`1.GreenPipes.IPipeContextSource<TContext>.Send(IPipe`1 pipe, CancellationToken cancellationToken)
   at GreenPipes.Agents.PipeContextSupervisor`1.GreenPipes.IPipeContextSource<TContext>.Send(IPipe`1 pipe, CancellationToken cancellationToken)
   at GreenPipes.Agents.PipeContextSupervisor`1.GreenPipes.IPipeContextSource<TContext>.Send(IPipe`1 pipe, CancellationToken cancellationToken)
   at MassTransit.Transports.ReceiveTransport`1.ReceiveTransportAgent.RunTransport()
   --- End of inner exception stack trace ---
   at MassTransit.Transports.ReceiveTransport`1.ReceiveTransportAgent.RunTransport()
   at MassTransit.Transports.ReceiveTransport`1.ReceiveTransportAgent.Run()
   at MassTransit.Transports.StartHostHandle.EndpointsReady(Task`1[] endpoints)
   at MassTransit.Transports.StartHostHandle.ReadyOrNot(Task`1[] endpoints, Task`1[] riders)
   at MassTransit.MassTransitBus.Handle.ReadyOrNot(Task`1 ready)
   at MassTransit.MassTransitBus.StartAsync(CancellationToken cancellationToken)
   at MassTransit.MassTransitBus.StartAsync(CancellationToken cancellationToken)
   at FaultConsumer.Program.Main(String[] args) in D:\code\masstransit\faultconsumer\Program.cs:line 52
   at FaultConsumer.Program.<Main>(String[] args)

1 Answers1

1

By changing the class from private to public, you expressed intent to MassTransit that the message type is a public message contract.

Public message contracts are not automatically deleted.

Private message contracts are automatically deleted.

By changing the visibility, you've changed the type, and it doesn't match the exchange that was already created on the broker.

You need to delete the mismatched exchange from the broker before restarting the application. This will eliminate the startup failure due to an invalid existing broker configuration.

The error is pretty detailed:

inequivalent arg 'durable' for exchange 'FaultConsumer:SubmitOrder' in vhost '/': received 'false' but current is 'true''

Chris Patterson
  • 28,659
  • 3
  • 47
  • 59