MySqlConnector
MySqlConnector copied to clipboard
Connectionpool not working as expected
Hello,
I have a problem using MySqlConnector. I'm using this code as a wrapper around the library:
namespace DatabaseLibrary
{
public class DatabaseHelper
{
public static int ExecuteNonQuery(string connectionString, string commandText, params object[] commandParameters)
{
using (var conn = new MySqlConnection(connectionString))
{
conn.Open();
return ExecuteNonQuery(conn, commandText, commandParameters);
}
}
public static int ExecuteNonQuery(MySqlConnection connection, string commandText, params object[] commandParameters)
{
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = connection;
cmd.CommandText = commandText;
cmd.CommandType = CommandType.Text;
int i = 1;
foreach (var p in commandParameters)
cmd.Parameters.Add(new MySqlParameter($"@{i++}", p));
int result = cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
return result;
}
public static MySqlDataReader ExecuteReader(string connectionString, string commandText, params object[] commandParameters)
{
var conn = new MySqlConnection(connectionString);
conn.Open();
return ExecuteReader(conn, commandText, commandParameters);
}
public static MySqlDataReader ExecuteReader(MySqlConnection connection, string commandText, params object[] commandParameters)
{
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = connection;
cmd.CommandText = commandText;
cmd.CommandType = CommandType.Text;
int i = 1;
foreach (var p in commandParameters)
cmd.Parameters.Add(new MySqlParameter($"@{i++}", p));
MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
cmd.Parameters.Clear();
return reader;
}
public static object ExecuteScalar(string connectionString, string commandText, params object[] commandParameters)
{
using (var conn = new MySqlConnection(connectionString))
{
conn.Open();
return ExecuteScalar(conn, commandText, commandParameters);
}
}
public static object ExecuteScalar(MySqlConnection connection, string commandText, params object[] commandParameters)
{
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = connection;
cmd.CommandText = commandText;
cmd.CommandType = CommandType.Text;
int i = 1;
foreach (var p in commandParameters)
cmd.Parameters.Add(new MySqlParameter($"@{i++}", p));
object result = cmd.ExecuteScalar();
cmd.Parameters.Clear();
return result;
}
}
}
As you can see everything should be wrapped with a using-directive. And where it is not, CommandBehavior.CloseConnection should do the job, as I understand it. All usages of MySqlDataReader are also enclosed with a usage directive. Now the following situation ocurres:
My application which is doing alot of queries and writes in multiple threads (I am using Task.Run(...) for that) is working fine for a few minutes. Then I get the following situation:
Not Flagged 28836 0 Worker Thread Worker Thread System.Private.CoreLib.dll!System.Threading.ManualResetEventSlim.Wait
Not Flagged 28797 0 Worker Thread Worker Thread System.Private.CoreLib.dll!System.Threading.ManualResetEventSlim.Wait
Not Flagged 28838 0 Worker Thread Worker Thread System.Private.CoreLib.dll!System.Threading.ManualResetEventSlim.Wait
Not Flagged 28808 0 Worker Thread Worker Thread System.Private.CoreLib.dll!System.Threading.ManualResetEventSlim.Wait
Not Flagged 28801 0 Worker Thread Worker Thread System.Private.CoreLib.dll!System.Threading.ManualResetEventSlim.Wait
Not Flagged 28798 0 Worker Thread Worker Thread System.Private.CoreLib.dll!System.Threading.ManualResetEventSlim.Wait
All of my worker threads are waiting for the semaphore in
MySqlConnector.dll!MySqlConnector.Core.ConnectionPool.GetSessionAsync C#
MySqlConnector.dll!MySql.Data.MySqlClient.MySqlConnection.CreateSessionAsync C#
MySqlConnector.dll!MySql.Data.MySqlClient.MySqlConnection.OpenAsync C#
MySqlConnector.dll!MySql.Data.MySqlClient.MySqlConnection.Open C#
DatabaseLibrary.dll!DatabaseLibrary.DatabaseHelper.ExecuteScalar C#
This is the state of the connection pool at that moment:
Name | Value | Type | |
---|---|---|---|
◢ | this | {MySqlConnector.Core.ConnectionPool} | MySqlConnector.Core.ConnectionPool |
▶ ConnectionSettings | {MySqlConnector.Core.ConnectionSettings} | MySqlConnector.Core.ConnectionSettings | |
Id | 1 | int | |
SslProtocols | None | System.Security.Authentication.SslProtocols | |
▶ m_cleanSemaphore | Current Count = 0 | System.Threading.SemaphoreSlim | |
m_generation | 0 | int | |
▶ m_hostSessions | null | System.Collections.Generic.Dictionary<string, int> | |
m_lastRecoveryTime | 841760172 | uint | |
m_lastSessionId | 20 | int | |
▶ m_leasedSessions | Count = 0 | System.Collections.Generic.Dictionary<string, MySqlConnector.Core.ServerSession> | |
▶ m_loadBalancer | {MySqlConnector.Core.FailOverLoadBalancer} | MySqlConnector.Core.ILoadBalancer {MySqlConnector.Core.FailOverLoadBalancer} | |
▶ m_logArguments | {object[1]} | object[] | |
▶ m_procedureCache | null | System.Collections.Generic.Dictionary<string, MySqlConnector.Core.CachedProcedure> | |
▶ m_reaperTask | Id = 1, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}" | System.Threading.Tasks.Task {System.Threading.Tasks.UnwrapPromise<System.Threading.Tasks.VoidTaskResult>} | |
▶ m_sessionSemaphore | Current Count = 0 | System.Threading.SemaphoreSlim | |
▶ m_sessions | Count = 20 | System.Collections.Generic.LinkedList<MySqlConnector.Core.ServerSession> | |
▶ Static members |
Why are there no leased sessions, twenty available sessions but the semaphore count is zero? I tried debugging this but I am not getting any further here. Maybe you have some idea?
On the server I am running 5.5.56-MariaDB, maybe thats the problem?
I am trying to run this on CentOS Linux release 7.4.1708 (Core) with Net Core Version 2.0.0. Both the application and the database run on the same server.
Which version of MySqlConnector are you using? There was a very similar bug to this that was fixed in 0.38.0: #469.
Thanks for the quick reply. I just updated today.
MySqlConnector> git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
MySqlConnector> git remote -v
origin https://github.com/mysql-net/MySqlConnector.git (fetch)
origin https://github.com/mysql-net/MySqlConnector.git (push)
MySqlConnector> git pull
Already up to date.
MySqlConnector>
So I guess I already have that bugfix. But indeed, this sounds like the bug I have.
Just to confirm: you’re saying that you do reproduce the problem with the latest code?
I do not know if it's the exact same bug as the one you linked me to. I am using a high connection timeout, so cancellation does not seem to be a problem in my case. My problem seems to be that queries are finished, sessions are given back to the pool but the semaphore is not updated correctly.
I do not know if it's the exact same bug as the one you linked me to.
It's probably not; I just wanted to rule out that you weren't possibly running into that one (e.g., by using an older package version).
Your code looks correct; I don't see an obvious reason why the connection pool would become exhausted even though sessions are being returned. Logs might help identify what's going on.
Use MySqlConnectorLogManager.Provider = new ConsoleLoggerProvider();
or one of the other logging providers documented here to enable logging.
Hey, I could reproduce the error with logging enabled:
[DEBUG] ConnectionPool Pool1 returning pooled Session1.20 to caller; LeasedSessionsCount=16
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ConnectionPool Pool1 found an existing session; checking it for validity
[DEBUG] ServerSession Session1.15 ServerVersion=5.5.56-MariaDB doesn't support reset connection; sending change user request
[DEBUG] ConnectionPool Pool1 found an existing session; checking it for validity
[DEBUG] ServerSession Session1.2 ServerVersion=5.5.56-MariaDB doesn't support reset connection; sending change user request
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ConnectionPool Pool1 returning pooled Session1.15 to caller; LeasedSessionsCount=17
[DEBUG] ConnectionPool Pool1 returning pooled Session1.2 to caller; LeasedSessionsCount=18
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ConnectionPool Pool1 returning pooled Session1.1 to caller; LeasedSessionsCount=19
[DEBUG] ServerSession Session1.18 entering FinishQuerying; SessionState=Querying
[DEBUG] ServerSession Session1.18 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.18 back
[DEBUG] ConnectionPool Pool1 found an existing session; checking it for validity
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ServerSession Session1.7 entering FinishQuerying; SessionState=Querying
[DEBUG] ServerSession Session1.7 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.7 back
[DEBUG] ServerSession Session1.18 ServerVersion=5.5.56-MariaDB doesn't support reset connection; sending change user request
[DEBUG] ConnectionPool Pool1 found an existing session; checking it for validity
[DEBUG] ServerSession Session1.7 ServerVersion=5.5.56-MariaDB doesn't support reset connection; sending change user request
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ServerSession Session1.9 entering FinishQuerying; SessionState=Querying
[DEBUG] ServerSession Session1.9 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.9 back
[DEBUG] ConnectionPool Pool1 returning pooled Session1.14 to caller; LeasedSessionsCount=20
[DEBUG] ServerSession Session1.8 entering FinishQuerying; SessionState=Querying
[DEBUG] ServerSession Session1.8 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.8 back
[DEBUG] ServerSession Session1.13 entering FinishQuerying; SessionState=Querying
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ServerSession Session1.13 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.13 back
[DEBUG] ConnectionPool Pool1 returning pooled Session1.18 to caller; LeasedSessionsCount=16
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ConnectionPool Pool1 returning pooled Session1.7 to caller; LeasedSessionsCount=17
[DEBUG] ServerSession Session1.1 entering FinishQuerying; SessionState=Querying
[DEBUG] ServerSession Session1.1 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.1 back
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ServerSession Session1.15 entering FinishQuerying; SessionState=Querying
[DEBUG] ServerSession Session1.15 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.15 back
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ServerSession Session1.6 entering FinishQuerying; SessionState=Querying
[DEBUG] ServerSession Session1.6 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.6 back
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ServerSession Session1.5 entering FinishQuerying; SessionState=Querying
[DEBUG] ServerSession Session1.5 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.5 back
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ServerSession Session1.3 entering FinishQuerying; SessionState=Querying
[DEBUG] ServerSession Session1.3 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.3 back
[DEBUG] ServerSession Session1.19 entering FinishQuerying; SessionState=Querying
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ServerSession Session1.19 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.19 back
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ServerSession Session1.11 entering FinishQuerying; SessionState=Querying
[DEBUG] ServerSession Session1.11 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.11 back
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ServerSession Session1.20 entering FinishQuerying; SessionState=Querying
[DEBUG] ServerSession Session1.20 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.20 back
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ServerSession Session1.2 entering FinishQuerying; SessionState=Querying
[DEBUG] ServerSession Session1.2 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.2 back
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ServerSession Session1.14 entering FinishQuerying; SessionState=Querying
[DEBUG] ServerSession Session1.14 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.14 back
[DEBUG] ServerSession Session1.7 entering FinishQuerying; SessionState=Querying
[DEBUG] ServerSession Session1.7 returning to Pool1
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ConnectionPool Pool1 receiving Session1.7 back
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ServerSession Session1.17 entering FinishQuerying; SessionState=Querying
[DEBUG] ServerSession Session1.17 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.17 back
[DEBUG] ServerSession Session1.18 entering FinishQuerying; SessionState=Querying
[DEBUG] ServerSession Session1.18 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.18 back
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ConnectionPool Pool1 found an existing session; checking it for validity
[DEBUG] ServerSession Session1.18 ServerVersion=5.5.56-MariaDB doesn't support reset connection; sending change user request
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ConnectionPool Pool1 returning pooled Session1.18 to caller; LeasedSessionsCount=5
[DEBUG] ServerSession Session1.12 entering FinishQuerying; SessionState=Querying
[DEBUG] ServerSession Session1.12 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.12 back
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ServerSession Session1.10 entering FinishQuerying; SessionState=Querying
[DEBUG] ServerSession Session1.10 returning to Pool1
[DEBUG] ServerSession Session1.16 entering FinishQuerying; SessionState=Querying
[DEBUG] ConnectionPool Pool1 receiving Session1.10 back
[DEBUG] ServerSession Session1.16 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.16 back
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ServerSession Session1.4 entering FinishQuerying; SessionState=Querying
[DEBUG] ServerSession Session1.4 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.4 back
[DEBUG] ConnectionPool Pool1 waiting for an available session
[DEBUG] ServerSession Session1.18 entering FinishQuerying; SessionState=Querying
[DEBUG] ServerSession Session1.18 returning to Pool1
[DEBUG] ConnectionPool Pool1 receiving Session1.18 back
[DEBUG] ConnectionPool Pool1 waiting for an available session
Done: 9983, Successful: 2006, Percentage: 0,20, Items/s: 3
[DEBUG] ConnectionPool Pool1 waiting for an available session
Done: 9984, Successful: 2006, Percentage: 0,20, Items/s: 1
[WARN] ConnectionPool Pool1 is empty; recovering leaked sessions
[DEBUG] ConnectionPool Pool1 recovered no sessions
[DEBUG] ConnectionPool Pool1 waiting for an available session
Done: 9985, Successful: 2006, Percentage: 0,20, Items/s: 1
[WARN] ConnectionPool Pool1 is empty; recovering leaked sessions
[DEBUG] ConnectionPool Pool1 recovered no sessions
[DEBUG] ConnectionPool Pool1 waiting for an available session
Done: 9986, Successful: 2006, Percentage: 0,20, Items/s: 1
[WARN] ConnectionPool Pool1 is empty; recovering leaked sessions
[DEBUG] ConnectionPool Pool1 recovered no sessions
[DEBUG] ConnectionPool Pool1 waiting for an available session
Maybe you are seeing something suspicious.
I can't explain how you're ending up in a state where m_sessions.Count == 20
but m_sessionSemaphore.CurrentCount == 0
; AFAICT ConnectionPool.Return
should release the semaphore whenever a session is added to m_sessions
.
Can you provide any more information about your table structure, types of commands, etc. that might help repro the problem? I assume MaximumPoolSize = 20
in your connection string? How long do you have to let your program run for before the problem happens? About how many SQL statements are executed before it happens? Does it happen consistently?
Yes my MaximumPoolSize is 20. Program runs for about 1-5minutes. It is happening consistently. When it happens there are already tenthousands of queries executed.
Another exception that is sometimes occuring is this:
Unhandled Exception: System.IO.EndOfStreamException: Expected to read 4 header bytes but only received 3.
Maybe it has something to do with the ConnectionPool situation?
I have already finished my work without multithreading. When I have more time I could give debugging it another try. Maybe I can reproduce it on a minimal example.
I think the smaller the connection pool is the faster the situation occurs.
Name | Value | Type | |
---|---|---|---|
◢ | Keys | Count = 4 | System.Collections.Generic.Dictionary<string, int>.KeyCollection |
[0] | "SELECT" | string | |
[1] | "DELETE" | string | |
[2] | "INSERT" | string | |
[3] | "UPDATE" | string | |
▶ Raw View | |||
◢ | Values | Count = 4 | System.Collections.Generic.Dictionary<string, int>.ValueCollection |
[0] | 38036 | int | |
[1] | 7444 | int | |
[2] | 61862 | int | |
[3] | 455 | int | |
▶ Raw View |
These are counts of commands that have been executed when I get stuck.
Another exception that is sometimes occuring is this:
Unhandled Exception: System.IO.EndOfStreamException: Expected to read 4 header bytes but only received 3.
Please provide more details on this exception, including the full call stack.
Maybe it has something to do with the ConnectionPool situation?
It's quite possible that it's putting the connection pool into an inconsistent internal state and error handling needs to be improved.
Unhandled Exception: System.IO.EndOfStreamException: Expected to read 4 header bytes but only received 3.
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Threading.Tasks.ValueTask`1.get_Result()
at MySqlConnector.Protocol.Serialization.ProtocolUtility.DoReadPayloadAsync(BufferedByteReader bufferedByteReader, IByteHandler byteHandler, Func`1 getNextSequenceNumber, ArraySegmentHolder`1 previousPayloads, ProtocolErrorBehavior protocolErrorBehavior, IOBehavior ioBehavior) in H:\ProgrammierungC#\RDFMatcher_NetCore\3rdparty\MySqlConnector\src\MySqlConnector\Protocol\Serialization\ProtocolUtility.cs:line 462
at MySqlConnector.Protocol.Serialization.ProtocolUtility.ReadPayloadAsync(BufferedByteReader bufferedByteReader, IByteHandler byteHandler, Func`1 getNextSequenceNumber, ArraySegmentHolder`1 cache, ProtocolErrorBehavior protocolErrorBehavior, IOBehavior ioBehavior) in H:\ProgrammierungC#\RDFMatcher_NetCore\3rdparty\MySqlConnector\src\MySqlConnector\Protocol\Serialization\ProtocolUtility.cs:line 454
at MySqlConnector.Protocol.Serialization.StandardPayloadHandler.ReadPayloadAsync(ArraySegmentHolder`1 cache, ProtocolErrorBehavior protocolErrorBehavior, IOBehavior ioBehavior) in H:\ProgrammierungC#\RDFMatcher_NetCore\3rdparty\MySqlConnector\src\MySqlConnector\Protocol\Serialization\StandardPayloadHandler.cs:line 37
at MySqlConnector.Core.ServerSession.ReceiveReplyAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) in H:\ProgrammierungC#\RDFMatcher_NetCore\3rdparty\MySqlConnector\src\MySqlConnector\Core\ServerSession.cs:line 604
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at MySqlConnector.Core.ServerSession.TryAsyncContinuation(Task`1 task) in H:\ProgrammierungC#\RDFMatcher_NetCore\3rdparty\MySqlConnector\src\MySqlConnector\Core\ServerSession.cs:line 1066
at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
at MySqlConnector.Core.ResultSet.<<ScanRowAsync>g__ScanRowAsyncAwaited|9_0>d.MoveNext() in H:\ProgrammierungC#\RDFMatcher_NetCore\3rdparty\MySqlConnector\src\MySqlConnector\Core\ResultSet.cs:line 217
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable`1.ConfiguredValueTaskAwaiter.GetResult()
at MySqlConnector.Core.ResultSet.<ReadAsync>d__7.MoveNext() in H:\ProgrammierungC#\RDFMatcher_NetCore\3rdparty\MySqlConnector\src\MySqlConnector\Core\ResultSet.cs:line 175
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at MySqlConnector.Core.ResultSet.Read() in H:\ProgrammierungC#\RDFMatcher_NetCore\3rdparty\MySqlConnector\src\MySqlConnector\Core\ResultSet.cs:line 166
at MySql.Data.MySqlClient.MySqlDataReader.Read() in H:\ProgrammierungC#\RDFMatcher_NetCore\3rdparty\MySqlConnector\src\MySqlConnector\MySql.Data.MySqlClient\MySqlDataReader.cs:line 31
at StreetSeg.Program.Main(String[] args) in H:\ProgrammierungC#\RDFMatcher_NetCore\StreetSeg\Program.cs:line 30
This is the full stacktrace for that exception. But that exception is not always happening when the deadlock happens, because I usually just let the program crash when it happens.
I just thought that maybe it's another symptom for the same underlying problem, for example the server is sending invalid data?
This could possibly be related to https://github.com/dotnet/corefx/issues/35393.
Closing issue without a consistent repro on a very old version of the library.