rebus-org / Rebus.SqlServer

:bus: Microsoft SQL Server transport and persistence for Rebus
https://mookid.dk/category/rebus
Other
43 stars 42 forks source link

SqlConnection factory constantly opens new connections in Two way transport #19

Closed matt-psaltis closed 6 years ago

matt-psaltis commented 6 years ago

Using the SqlAllTheWay sample, we see hundreds of new SqlConnections being opened and closed per second through the DbConfig.GetDbConnection connection factory. There's only one worker and no messages are ever put onto the bus.

Is this expected behaviour?

mookid8000 commented 6 years ago

I would not expect hundreds per second – that figure sounds very high, it should be more like a couple of connections per second until Rebus' workers back off and increase the polling interval.

Let me just see if I can find something weird in the sample... brb

mookid8000 commented 6 years ago

When I let the SqlAllTheWay sample run idle on my own machine, I get this result from SQL Profiler:

image

Rebus' default backoff strategy says to wait 100 ms between polling the transport for the first 10 seconds of running idle, thereafter increasing the wait interval to 250 ms. The captured events from the profiler seem to pretty much reflect this.

If I change the interval to 5 s, I get the following profiler output:

image

which is exactly what I expected.

If you want to decrease the polling frequency, you can customize the backoff times like this:

Configure.With(...)
    .(...)
    .Options(o => {
        o.SetBackoffTimes(
            TimeSpan.FromSeconds(0.1), // 1st second of running idle: 100 ms
            TimeSpan.FromSeconds(0.5), // 2nd second of running idle: 500 ms
            TimeSpan.FromSeconds(1),   // 3rd second of running idle: 1 s
            TimeSpan.FromSeconds(5)    // the rest of the time running idle: 5 s
        );
    })
    .Start();

How did you find out that hundreds of SqlConnections were being opened per second?

matt-psaltis commented 6 years ago

Thanks @mookid8000. Really appreciate you taking a look at this so quickly. I was approaching this from the point of view of a suspected memory leak in our application. We had an unexplained memory growth rate during application startup. Using VS2017 profiling tools I could see a large number of SqlConnection objects being created in the first few seconds of our application starting up. I took some memory snapshots and repeated that against the SqlAllTheWay sample. The profiling was reporting a growth of 257 SqlConnection objects after 3 seconds. Best working theory I have is Sql Connection pooling but it doesn't exactly fit.

Good to know the SqlServer transport polling isn't just a new SqlCommand but a full SqlConnection each time. My mental model was wrong, I assumed a connection would be reused until it had successfully processed a message - Don't really know why I thought that, another Service bus implementation maybe.

Thanks again - I'll try and stop wasting your time :)