StackExchange.Redis icon indicating copy to clipboard operation
StackExchange.Redis copied to clipboard

ConnectTimeout when sending multiple GET commands immediately after service start

Open incloudss opened this issue 2 years ago • 3 comments

Hi,

I am getting exception: It was not possible to connect to the redis server(s). ConnectTimeout" when sending ~20 GET commands immediately after service start, parallalely(each GET is invoked from different thread). I am sure i have singleton instance of RedisCacheClient, as i am registering it through StackExchange.Redis.Extensions.AspNetCore package.

The workaround i found for now is to send one GET command after starting service, from main thread, and then proceed to sending multiple requests paralelly, and it works flawlessly.

Full exception stacktrace
at StackExchange.Redis.ConnectionMultiplexer.Connect(ConfigurationOptions configuration, TextWriter log) in /_/src/StackExchange.Redis/ConnectionMultiplexer.cs:line 1032
at StackExchange.Redis.Extensions.Core.Implementations.RedisCacheConnectionPoolManager.<EmitConnection>b__10_0()
at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Polly.AsyncPolicy.<>c__DisplayClass40_0.<<ImplementationAsync>b__0>d.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at Polly.AsyncPolicy.<>c__DisplayClass40_0.<<ImplementationAsync>b__0>d.MoveNext()
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
at Polly.AsyncPolicy.<>c__DisplayClass40_0.<<ImplementationAsync>b__0>d.MoveNext()
at Polly.AsyncPolicy.<>c__DisplayClass40_0.<<ImplementationAsync>b__0>d.MoveNext()
at Polly.AsyncPolicy.<>c__DisplayClass40_0.<<ImplementationAsync>b__0>d.MoveNext()
at Polly.AsyncPolicy.<>c__DisplayClass40_0.<<ImplementationAsync>b__0>d.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at Polly.Retry.AsyncRetryEngine.<ImplementationAsync>d__0`1.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Polly.Retry.AsyncRetryEngine.<ImplementationAsync>d__0`1.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at Polly.Retry.AsyncRetryEngine.<ImplementationAsync>d__0`1.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at Polly.Retry.AsyncRetryEngine.<ImplementationAsync>d__0`1.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
at Polly.AsyncPolicy.<>c__DisplayClass40_0.<<ImplementationAsync>b__0>d.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Lazy`1.CreateValue()
at StackExchange.Redis.Extensions.Core.Implementations.RedisCacheConnectionPoolManager.GetConnection()
at StackExchange.Redis.Extensions.Core.Implementations.RedisDatabase.SubscribeAsync[T](RedisChannel channel, Func`2 handler, CommandFlags flags)
at MotoGo.ExpressBus.ExpressBus.<Receive>d__9`1.MoveNext() in D:\Repos\MotoGo\src\MotoGo.ExpressBus\ExpressBus.cs:line 120
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
--- End of stack trace from previous location ---
at Polly.Retry.AsyncRetryEngine.<ImplementationAsync>d__0`1.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Polly.Retry.AsyncRetryEngine.<ImplementationAsync>d__0`1.MoveNext()
at Polly.Retry.AsyncRetryEngine.<ImplementationAsync>d__0`1.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at Polly.Retry.AsyncRetryEngine.<ImplementationAsync>d__0`1.MoveNext()
at Polly.Retry.AsyncRetryEngine.<ImplementationAsync>d__0`1.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at Polly.Retry.AsyncRetryEngine.<ImplementationAsync>d__0`1.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at Polly.Retry.AsyncRetryEngine.<ImplementationAsync>d__0`1.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at MotoGo.CacheLoader.HostedService.<StartAsync>d__10.MoveNext() in D:\Repos\MotoGo\src\MotoGo.CacheLoader\HostedService.cs:line 54```
</details>

incloudss avatar May 10 '22 20:05 incloudss

Me too! I thought this was my Docker environment being silly, but turns out I'm not the only person.

Watching this.

OriginalArkus avatar May 14 '22 17:05 OriginalArkus

Given the symptoms, you're likely hitting threadpool exhaustion overall in the app, early, before it grows. As an experiment (bain-aid, not a real fix) you can try ThreadPool.SetMinThreads() before the connection runs to see how it behaves. There's no magic bullet here because it'll depend on your environment, budget, how many cores are available, what work is competing, etc. But if you're quickly going full parallel and synchronously so when the app starts, you may be exhausting the available thread pool very rapidly.

Generally, you want to go async here to schedule work and not tie up threads with waiting and inaction, but that may be a non-trivial change...it is the best long term play though :)

NickCraver avatar May 28 '22 19:05 NickCraver

We're experiencing the same issue with .net 4.6.2.

garpunkal avatar Jun 22 '22 07:06 garpunkal

Closing this out to tidy up - best advice we have is above!

NickCraver avatar Aug 21 '22 03:08 NickCraver