question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Connections from the pool are not reused when using async methods in parallel

See original GitHub issue

Whem I’m using async methods (like FirstOrDefaultAsync) to get a result from the Database inside a Parallel.For, the connections are not correctly reused from the connection pool.

The connections will rise to the configured Max Pool Size and after some time (around 1-2 minutes on my machine using localdb), exceptions will be thrown.

Using either async methods and a normal for-loop or non-async methods an a Parallel.For-loop, the connections are properly reused and I can observe that a normal for-loop uses 1 connection and a Parallel.For-loop uses 4 connections which corresponds to MaxDegreeOfParallelism.

Exception message:
System.InvalidOperationException occurred
  HResult=0x80131509
  Message=Timeout expired.  The timeout period elapsed prior to obtaining a connection from the pool.  This may have occurred because all pooled connections were in use and max pool size was reached.
Stack trace:
   at System.Data.Common.ADP.ExceptionWithStackTrace(Exception e)
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.<OpenAsync>d__31.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable.AsyncEnumerator.<BufferlessMoveNext>d__9.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.<ExecuteImplementationAsync>d__33`2.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.<ExecuteImplementationAsync>d__33`2.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable.AsyncEnumerator.<MoveNext>d__8.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.SelectAsyncEnumerable`2.SelectAsyncEnumerator.<MoveNext>d__4.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.<_FirstOrDefault>d__82`1.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.Query.Internal.TaskResultAsyncEnumerable`1.Enumerator.<MoveNext>d__3.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.SelectAsyncEnumerable`2.SelectAsyncEnumerator.<MoveNext>d__4.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.<MoveNext>d__5.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at EfPoolingTest.UnitTest1.<>c.<NormalContextParallel>b__4_0(Int32 i) in C:\Users\xxx\documents\visual studio 2017\Projects\EfPoolingTest\EfPoolingTest\UnitTest1.cs:line 70
   at System.Threading.Tasks.Parallel.<>c__DisplayClass19_0`1.<ForWorker>b__1(RangeWorker& currentWorker, Int32 timeout, Boolean& replicationDelegateYieldedBeforeCompletion)

Steps to reproduce

  • Clone https://github.com/wertzui/EfPoolingTest and open the project
  • Run the “ViewConnections.sql” script to see that there are no connections open (beside the 2 used for the script)
  • Run the test “NormalContextParallelAsyncConfigureAwaitFalse” (I suggest running in Debug mode, so you can see the output)
  • Run the “ViewConnections.sql” script multiple times to see the connections increase.
  • After some time you will also get an exception
  • Run the other tests and observe the connection count

Further technical details

EF Core version: 2.0.0 (also tested with 1.1.3) Database Provider: Microsoft.EntityFrameworkCore.SqlServer/localdb Operating system: Windows 10 FCU IDE: Visual Studio 2017 15.4.1

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:10 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
ralmsdevelopercommented, Oct 27, 2017

Hello @wertzui, Seeing better, I made this little change in the Context and it was more satisfying, until it reaches 100, but then reduce!

using Microsoft.EntityFrameworkCore;
using System.Data.SqlClient;

namespace EfCoreLongStringTest
{
    public class MyContext : DbContext
    {
        public DbSet<MyTable> MyTable { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
                optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Initial Catalog=EfCorePoolingTest;Integrated Security=true;",
                    options => options.EnableRetryOnFailure());
            }
            base.OnConfiguring(optionsBuilder);
        }

        public override void Dispose()
        {
            SqlConnection.ClearPool((SqlConnection)Database.GetDbConnection());  
            base.Dispose(); 
        }
    }
}

If you can take a look at this it would be good, because the EF team would have a better direction!

1reaction
wertzuicommented, Oct 27, 2017

I tried your example and the behavior does not change (100 connections and exception after some time). I added that test case to my repo.

Afaik calling context.Database.CloseConnection() does not really close the connection, but returns it to the pool.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Connections from the pool are not reused when using ...
Whem I'm using async methods (like FirstOrDefaultAsync ) to get a result from the Database inside a Parallel.For , the connections are not...
Read more >
SqlClient connection pool maxed out when using async
1 Answer 1 · 1. Actually, no. · 1 · In fact, by allowing more requests to be handled by the same server,...
Read more >
.NET Framework Connection Pool Limits and the new ...
NET maintains a pool of HTTP connections that can be reused instead of opening a new one for each request. The post details...
Read more >
Using Asynchronous Methods in ASP.NET 4.5
This tutorial will teach you the basics of building an asynchronous ASP.NET Web Forms application using Visual Studio Express 2012 for Web, ...
Read more >
Overview of C# Async Programming with Thread pools and ...
Using a thread pool reduces the performance penalty by sharing and recycling threads; it exists primarily to reuse threads and to ensure the ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found