Redis Timeout Expired message on GetClient call - redis

I hate the questions that have "Not Enough Info". So I will try to give detailed information. And in this case it is code.
Server:
64 bit of https://github.com/MSOpenTech/redis/tree/2.6/bin/release
There are three classes:
DbOperationContext.cs: https://gist.github.com/glikoz/7119628
PerRequestLifeTimeManager.cs: https://gist.github.com/glikoz/7119699
RedisRepository.cs https://gist.github.com/glikoz/7119769
We are using Redis with Unity ..
In this case we are getting this strange message:
"Redis 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.";
We checked these:
Is the problem configuration issue
Are we using wrong RedisServer.exe
Is there any architectural problem
Any idea? Any similar story?
Thanks.
Extra Info 1
There is no rejected connection issue on server stats (I've checked it via redis-cli.exe info command)

I have continued to debug this problem, and have fixed numerous things on my platform to avoid this exception. Here is what I have done to solve the issue:
Executive summary:
People encountering this exception should check:
That the PooledRedisClientsManager (IRedisClientsManager) is registed in a singleton scope
That the RedisMqServer (IMessageService) is registered in a singleton scope
That any utilized RedisClient returned from either of the above is properly disposed of, to ensure that the pooled clients are not left stale.
The solution to my problem:
First of all, this exception is thrown by the PooledRedisClient because it has no more pooled connections available.
I'm registering all the required Redis stuff in the StructureMap IoC container (not unity as in the author's case). Thanks to this post I was reminded that the PooledRedisClientManager should be a singleton - I also decided to register the RedisMqServer as a singleton:
ObjectFactory.Configure(x =>
{
// register the message queue stuff as Singletons in this AppDomain
x.For<IRedisClientsManager>()
.Singleton()
.Use(BuildRedisClientsManager);
x.For<IMessageService>()
.Singleton()
.Use<RedisMqServer>()
.Ctor<IRedisClientsManager>().Is(i => i.GetInstance<IRedisClientsManager>())
.Ctor<int>("retryCount").Is(2)
.Ctor<TimeSpan?>().Is(TimeSpan.FromSeconds(5));
// Retrieve a new message factory from the singleton IMessageService
x.For<IMessageFactory>()
.Use(i => i.GetInstance<IMessageService>().MessageFactory);
});
My "BuildRedisClientManager" function looks like this:
private static IRedisClientsManager BuildRedisClientsManager()
{
var appSettings = new AppSettings();
var redisClients = appSettings.Get("redis-servers", "redis.local:6379").Split(',');
var redisFactory = new PooledRedisClientManager(redisClients);
redisFactory.ConnectTimeout = 5;
redisFactory.IdleTimeOutSecs = 30;
redisFactory.PoolTimeout = 3;
return redisFactory;
}
Then, when it comes to producing messages it's very important that the utilized RedisClient is properly disposed of, otherwise we run into the dreaded "Timeout Expired" (thanks to this post). I have the following helper code to send a message to the queue:
public static void PublishMessage<T>(T msg)
{
try
{
using (var producer = GetMessageProducer())
{
producer.Publish<T>(msg);
}
}
catch (Exception ex)
{
// TODO: Log or whatever... I'm not throwing to avoid showing users that we have a broken MQ
}
}
private static IMessageQueueClient GetMessageProducer()
{
var producer = ObjectFactory.GetInstance<IMessageService>() as RedisMqServer;
var client = producer.CreateMessageQueueClient();
return client;
}
I hope this helps solve your issue too.

Related

RedisTimeoutException is crashing my aspnet core application

When my application traffic gets high, StackExchange.Redis starts to throw RedisTimeoutException and after some minutes, my asp.net core application crashes.
The Windows event viewer says The process was terminated due to an unhandled exception. Exception Info: StackExchange.Redis.RedisTimeoutException.
Ok, I understand that there is some issue between my app and Redis, but while I can't solve this, how can I prevent the application to shutdown?
Inside startup.cs, I tried to put:
TaskScheduler.UnobservedTaskException += (object sender, UnobservedTaskExceptionEventArgs eventArgs) =>
{
eventArgs.SetObserved();
eventArgs.Exception.Handle(ex => true);
};
no success....
Any help ?
Tks
How are you creating the ConnectionMultiplexer instances?
Maybe you are not reusing a multiplexer instance and creating a lot of connections.
The ConnectionMultiplexer object should be shared and reused between callers. It is not recommended to create a ConnectionMultiplexer per operation. Check StackExchange.Redis documentation here for more information.
About the exception handling on Asp.NET Core, you can use the UseExceptionHandler diagnostic middleware to handle exceptions globally. Check this article for a complete explanation
Have you tried to put the block that throws the exception in a try/catch block? And perhaps make it try a few times with Polly when there is a timeout. https://github.com/App-vNext/Polly
Normally it shouldn't terminate your app, but since you didn't share any code, We can not be sure.
If you create a service class like below, you can encapsulate all of your redis calls, therefore catch the exceptions.
public class EmptyClass
{
private readonly ConnectionMultiplexer _connectionMultiplexer;
public EmptyClass(ConnectionMultiplexer connectionMultiplexer)
{
_connectionMultiplexer = connectionMultiplexer;
}
public void Execute(Action<ConnectionMultiplexer> action)
{
try
{
action.Invoke(_connectionMultiplexer);
}
catch(RedisTimeoutException ex)
{
}
}
public void TestRun()
{
Execute((ConnectionMultiplexer obj) =>
{
//do stuff with obj.
});
}
}
I agree with #thepirat000's answer, reason is ConnectionMultiplexer
You can use ConnectionMultiplexer according your Redis package (StackExchange.Redis or ServiceStack.Redis) and according your deployment environment
In my aspnet core application (like you) i have used StackExchange.Redis and i have deployed to windows server without any error within below Startup.cs settings
#region Redis settings ConnectionMultiplexer
services.AddDataProtection().ProtectKeysWithDpapi(protectToLocalMachine: true);
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(#"c:\temp-keys"))
.ProtectKeysWithDpapiNG($"CERTIFICATE=HashId:{thumbPrint}", flags: Microsoft.AspNetCore.DataProtection.XmlEncryption.DpapiNGProtectionDescriptorFlags.None);
services.AddDataProtection().ProtectKeysWithDpapiNG();
services.Configure<StorageConfiguration>(new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json", optional: true, reloadOnChange: true).Build());
var redisConf = Configuration.GetSection("RedisConnection").Get<RedisConnection>();
ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(redisConf.Host.ToString() + ":" + redisConf.Port.ToString());
services.AddDataProtection().PersistKeysToStackExchangeRedis(redis, "DataProtection-Keys");
services.AddSingleton<IConnectionMultiplexer>(ConnectionMultiplexer.Connect(redisConf.Host.ToString() + ":" + redisConf.Port.ToString()));
#endregion
Look here for basic usage https://stackexchange.github.io/StackExchange.Redis/Basics.html

easynetQ delayed respond/request resulting in timeout

I've run into a problem with using the request/respond pattern of EasyNetQ while using it on our server (Windows Server 2008). Not able to reproduce it locally at the moment.
The setup is we have 2 windows services (running as console applications for testing) which are connected through the request/respond pattern in EasyNetQ. This has been working as expected until recently on the server where the request side does not "consume" the responses until after the request timeouts.
I have included 2 links to pastebin which contain the console logging of EasyNetQ which will hopefully make my problem a bit more clear.
RequestSide
RespondSide
Besides that, my request code looks like this:
var request = new foobar();
var response = _bus.Request<foobar, foobar2>(request);
and on the respond side:
var response = new response();
_bus.Respond<foobar, foobar2>(request =>
{
try
{
....
return response;
}
catch (Exception e)
{
....
return response;
}
});
As I've said, the request side sends the request as expected and the respond side consumes/catches it. This works as it should, but when the respond side is done processing and responds (which it does, the messages can be seen in the RabbitMQ management thingy) the request doesn't consume/catch the response until after the request has timed out (default timeout is 10s, tried setting to 60s aswell, makes no difference). This is also evident in the logs linked above as you'll see on the RequestSide, with the 5 or so messages received from the response queue which previously timed out.
I've tried using RespondAsync in case the processing was taking too long and messing something up, didn't help. Tried using both RespondAsync & RequestAsync, just messed everything up even more (I was probably doing something wrong with the request :)).
I might be missing something, but I'm not sure what to try from here.
EDIT: Noticed I messed something up. As well as added more context below:
The IBus used for the request/response is created and injected with Ninject:
class FooModule : NinjectModule
{
public override void Load()
{
Bind<IBus>().ToMethod(ctx => RabbitHutch.CreateBus("host=localhost", x => x.Register<IEasyNetQLogger>(_ => logger))).InSingletonScope();
}
}
And it's all tied together by the service being constructed using Topshelf with Ninject like so:
static void Main(string[] args)
{
HostFactory.Run(x =>
{
x.UseNinject(new FooModule());
x.Service<FooService>(s =>
{
s.ConstructUsingNinject();
s.WhenStarted((service, control) => service.Start(control));
s.WhenStopped((service, control) => service.Stop(control));
});
x.RunAsLocalSystem();
});
}
The Topshelf setup has all been tested pretty thoroughly and it works as intended, and should not really be relevant for the request/respond problem, but I thought I would provide a bit more context.
I had this same issue, my problem was i set the timeout only in the response but not in the request side, after i set the timeoute in both side it worked fine
my connection for eg.
host=hostname;timeout=120;virtualHost=myhost;username=myusername;passw
ord=mypassword

WCF contract mismatch error only when running in parallel

I have a load tester that calls my WCF service and I've built it with options to run the calls in parallel or not. Only when running in parallel, I get the following error for all threads: "The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error."
This is more or less my code:
if (runMultiThreaded)
{
ParallelOptions options = new ParallelOptions();
options.MaxDegreeOfParallelism = System.Environment.ProcessorCount;
ParallelLoopResult loopResult = Parallel.For(0, numberOfTimesToTest, options,
(i, loopState) =>
{
myService.MyOperation();
if (loopState.ShouldExitCurrentIteration) return;
});
}
else
{
for (int i = 0; i < test1NumberOfRuns; i++)
{
myService.MyOperation();
}
}
Any ideas? Let me know if you need more details.
UPDATE: myService is an instance of my service's operation contract interface that was created with a ChannelFactory using the CreateChannel method.
Thanks!
I'm assuming your myService is a ClientBase<T> subclass or a channel created explicitly via ChannelFactory<T>::CreateChannel? If so those instances are not guaranteed to be thread safe and you so you need an instance per worker thread.

What WCF Exceptions should I retry on failure for? (such as the bogus 'xxx host did not receive a reply within 00:01:00')

I have a WCF client that has thrown this common error, just to be resolved with retrying the HTTP call to the server. For what it's worth this exception was not generated within 1 minute. It was generated in 3 seconds.
The request operation sent to xxxxxx
did not receive a reply within the
configured timeout (00:01:00). The
time allotted to this operation may
have been a portion of a longer
timeout. This may be because the
service is still processing the
operation or because the service was
unable to send a reply message. Please
consider increasing the operation
timeout (by casting the channel/proxy
to IContextChannel and setting the
OperationTimeout property) and ensure
that the service is able to connect to
the client
How are professionals handling these common WCF errors? What other bogus errors should I handle.
For example, I'm considering timing the WCF call and if that above (bogus) error is thrown in under 55 seconds, I retry the entire operation (using a while() loop). I believe I have to reset the entire channel, but I'm hoping you guys will tell me what's right to do.
What other
I make all of my WCF calls from a custom "using" statement which handles exceptions and potential retires. My code optionally allows me to pass a policy object to the statement so I can easily change the behavior, like if I don't want to retry on error.
The gist of the code is as follows:
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ProxyUsing<T>(ClientBase<T> proxy, Action action)
where T : class
{
try
{
proxy.Open();
using(OperationContextScope context = new OperationContextScope(proxy.InnerChannel))
{
//Add some headers here, or whatever you want
action();
}
}
catch(FaultException fe)
{
//Handle stuff here
}
finally
{
try
{
if(proxy != null
&& proxy.State != CommunicationState.Faulted)
{
proxy.Close();
}
else
{
proxy.Abort();
}
}
catch
{
if(proxy != null)
{
proxy.Abort();
}
}
}
}
You can then use the call like follows:
ProxyUsing<IMyService>(myService = GetServiceInstance(), () =>
{
myService.SomeMethod(...);
});
The NoInlining call probably isn't important for you. I need it because I have some custom logging code that logs the call stack after an exception, so it's important to preserve that method hierarchy in that case.

Entity Framework objectcontext ending prematurely

Hello I am getting the error "ObjectContext instance has been disposed and can no longer be used for operations that require a connection". When I run some methods from a wcf service. All of them use a new context object and most of them run without issue. However this one keeps giving the error above although several methods with similar implementations succeed several lines above in my code:
public CustomAuthentication.WebService.Application GetApplicationByUrl(string url)
{
try
{
using (AuthenticationEntities2 auth = new AuthenticationEntities2())
{
Application app = auth.Applications.Where(a => a.Url.Contains(url)).FirstOrDefault();
return app;
}
}
catch (Exception ex)
{
throw new FaultException(ex.Message + "\r\n" + ex.StackTrace + "\r\n" + ex.InnerException);
}
}
I also initially saw this error from vs "The underlying connection was closed: A connection that was expected to be kept alive was closed by the server." So I thought it was an issue serializing objects in my wcf service. So I did some tracing on the service and discovered the error above. So now believe its entity related. Any ideas?
Try to turn off lazy loading on your ObjectContext. Most probably your Application contains navigation properties which trigger lazy loading during serialization.