MassTransit timeouts under load on .NETFramework under IIS

Viewed 37

Under load in production we receive "RabbitMQ.Client.Exceptions.ConnectFailureException" connection failed and "MassTransit.RequestTimeoutException" timeout waiting for response. The consumer does receive the message and send it back. It's like the web app isn't listening, or unable to accept the connection.

We're running an ASP.NET web application ( not MVC ) on .NET Framework 4.6.2 on Windows Server 2019 on IIS. We're using MassTransit 7.0.4. In production, under load, we can get some exceptions dealing with sockets on RabbitMQ or timeouts from masstransit. It's difficult to reproduce them in Dev. RabbitMQ is in a mirror, it seems to happen once we turn on a high-load service that bumps from 140 message/sec to 250 message/sec.

I have a few questions about the code architecture, and then if anyone else is running into these kinds of timeout issues.

Questions:

  1. Should I have static scope for the IBusControl? IE, should it be static inside Global asax? And does it matter at all if it's a singleton underneath?
  2. Should I create a new IBusControl and start it per request ( maybe stick it in Application BeginRequest ). Would that make a difference?
  3. Would adding another worker process affect the total number of open connections I'm able to make -- If this is a resource issue ( exhausting threads, connections or some resource ).

Exceptions:

MassTransit.RequestTimeoutException
Timeout Waiting for response
Stacktrace:
System.Runtime.ExceptionServices.ExceptionDispathInfo.Throw
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification
MassTransit.Clients.ResponseHandlerConnectionHandle`1+<GetTask>d_11.MoveNext
System.Threading.ExecutionContext.RunInternal



RabbitMQ.Client.Exceptions.ConnectFailureException
Connection failed
Statcktrace:
RabbitMQ.Client.Impl.SocketFrameHandler.ConnectOrFail
RabbitMQ.Client.Impl.SocketFrameHandler.ConnectUsingAddressFamily
RabbitMQ.Client.Impl.SocketFrameHandler..ctor
RabbitMQ.Client.ConnectionFactory.CreateFrameHandler
RabbitMQ.Client.EndPointResolverExtensions.SelectOne
RabbitMQ.Client.ConnectionFactory.CreateConnection

How Our Code Works ( overview )

Static IBusControl that is instantiated the first time someone tries to produce a message. The whole connection and send code is a little large to put in here ( connection factory and other metric classes, but below are the interesting parts ).

    Static IBusControl B;
    
    B = Bus.Factory.CreateUsingRabbitMq(x =>
    {
        hostAddress = host.HostAddress;
        x.Host(new Uri(host.HostAddress), h =>
        {
            h.Username(host.UserName);
            h.Password(host.Password);
        });
        x.Durable = false;
        x.SetQueueArgument("x-message-ttl", 600000);
    });
    B.Start(new TimeSpan(0, 0, 10));
    
    // Then send the Actual Messages
    // Generic with TRequest and TResponse : class BaseMessage
    // Pulling the code out of a few different classes
    
    string serviceAddressString = string.Format("{0}/{1}?durable={2}", HostAddress, ChkMassTransit.QueueName(typeof(TRequest), typeof(TResponse)), false ? "true" : "false");
    Uri serviceAddress = new Uri(serviceAddressString);
    RequestTimeout rt = RequestTimeout.After(0, 0, 0, 0, timeout.Value);
    IRequestClient<TRequest> reqClient = B.CreateRequestClient<TRequest>(serviceAddress, rt);
    var v = reqClient.GetResponse<TResponse>(request, sendInfo.CT, sendInfo.RT);
    if ( v.Wait(timeoutMS) ) { /*do some stuff*/ }
1 Answers

First, I find your lack of async disturbing. Using Wait or anything like it on TPL-based code is a recipe for death and destruction, pain and suffering, dogs and cats living together, etc.

  1. Yes, you should have a single bus instance that is started when the application starts. Since you're doing request/response, set AutoStart = true on the bus configurator to make sure it's all warmed up and ready.

  2. Never, no, one bus only!

  3. Each bus instance only has a single connection, so you shouldn't see any resource issues related to capacity on RabbitMQ.

MassTransit 7.0.4 is really old, you might consider the easy upgrade 7.3.1 and see if that improves things for you. It's the last version of the v7 codebase available.

Related