RedisTimeoutException is crashing my aspnet core application - asp.net-core

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

Related

Service not calling OnShutdown() when windows shuts down

I have .net core console application, which is hosted as windows service.
I want to catch an event if the user logs off/shutdown the computer.
I have found ways to catch this event in .net framework (here & here).
But I cant figure out how to achieve this in .net core.
To create service I am using "ServiceBase" class. Sample code is as given below:
public class MyService : ServiceBase
{
readonly string LogPath = "D:\\TestAppService.txt";
#region Constructors
public MyService()
{
this.CanShutdown = true;
}
#endregion
#region Protected Functions
protected override void OnStart(string[] args)
{
//your code here
// call the base class so it has a chance
// to perform any work it needs to
base.OnStart(args);
}
protected override void OnStop()
{
//your code here
// Call the base class
base.OnStop();
}
protected override void OnShutdown()
{
using (StreamWriter sw = File.AppendText(LogPath))
{
sw.WriteLine("shutdown == true");
}
//your code here
base.OnShutdown();
}
#endregion
}
The OnStop and OnStart methods are being called.
but when I shutdown the computer my OnShutdown method is not called.
According to aspisof.net, you should be able to use the SessionEnding API. This is because it is listed as being exposed in the windows Compatibility Pack - available on NuGet here.
This article on learn.microsoft.com shows how you can include it in a .NET Core application.
tl;dr
Add the NuGet package
Target Windows only
One thing to note: this was originally designed to be a temporary fix for porting Windows specific .NET code over to .NET Core.
The more accepted way to implement Windows only features is to move as much code to .NET Standard libraries as possible, and to use conditional compilation directives to include platform specific code when building for that platform.
By design dotnet core is not "friendly" with platform specific stuff
(like listening to log off event seems to me).
The solution I use in one of Windows-hosted services is described here.
When application domain is forced to close by operating system on shutdown - there is a room for using AppDomain event handlers.

How to detect application pool restart of a WCF service?

In my WCF service I use a static dictionary to hold some resource intensive data. I need to clean up the resources when the application pool gets recycled. Is there any method (for example event) by which I can detect that application pool is being recycled?
if your application pool gets recycled all your static objects will be reset. you can clean all external resources (like files or ...) when creating an instance of your static dictionary. something like this:
public static partial class ProjectValues
{
public static ConcurrentDictionary<string, string> MessageDictionary { private set; get; }
static ProjectValues()
{
try
{
MessageDictionary = new ConcurrentDictionary<string, string>();
//then clear the resource here
}
catch (Exception ex)
{
return;
}
}
}
Is there any method( for example event) by which I can detect that
application pool is being recycled?
Kinda.
According to Phill Haack, IIS exposes a static method called HostingEnvironment.RegisterObject, which allows you to pass implementations of IRegisteredObject into it.
In theory, this tells IIS to call the IRegisteredObject.Stop operation before it decides to kill the w3wp.exe process your app is running in.
I say in theory because this approach is not fail-safe and there are instances where the AppDomain can go away without calling, or even to call but then shut down anyway, before you're finished doing your cleanup.

Redis Timeout Expired message on GetClient call

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.

How do I force GlassFish 2 to load EJBs on startup?

We're using EJB3 on GlassFish v2.
My application includes a GenericServlet called StartupServlet, which has an init method. java.util.TimerTask pollers started from this method cannot lookup facades from the InitialContext.
However if I make an HTTP request and do a lookup, it succeeds. Therefore I have a workaround now where my poller startup code makes an HTTP connection to a page which looks up the interfaces they need.
How can I rearrange my application so I don't need to use such a hack? If possible the solution needs to work on GFv3 as well.
Thanks in advance for your help!
On GF 2, I have a servlet that on start ensures that my timer is created. This looks up a remote session bean and calls it successfully from the init() (not actual code, distilled down to the important parts):
#EJB(name="TimerSessionRef", beanInterface=TimerSessionRemote.class)
public class StartTimers extends HttpServlet {
#Override
public void init() throws ServletException {
super.init();
try {
Context ctx = new InitialContext();
TimerSessionRemote timerSession = (TimerSessionRemote) ctx.lookup("java:comp/env/TimerSessionRef");
timerSession.createTimer();
} catch (NamingException ex) {
logger.blah();
}

Testing Castle windsor Component with PerWebRequest lifestyle

I'm trying to do some testing with castle windsor involved, in one of my tests I want to check the windsor installers, so I check that the container can resolve my components given its interface.
So far, so good, the problem starts when the component has PerWebRequest lifestyle in its installer, at first it complained about HttpContext.Current is null, having that one solved creating a fake Context in test setup I'm now having this exception in nunit test
System.Exception : Looks like you forgot to register the http module Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule
Add '' to the section on your web.config. If you're running IIS7 in Integrated Mode you will need to add it to section under
As I'm running this from NUnit, how I can register the module or class in windsor so it works, or how can be mocked, as in this test is not really a web request, just checking that the container resolve the type.
And also this same thing will happen if I make any integration tests with this component outside a real webrequest, is there any way to make this work or really mock a web request so this tests can be run?
Tranks in advance
Fer
In your test you could subscribe to the ComponentModelCreated event and change the lifestyle of your per-web-request components to something else. (example).
If you're writing an integration test with the scope of a single request, singleton should do.
If you're writing an integration test that spans multiple requests, you could use a contextual lifestyle to simulate the scope of requests.
Edit: including code from example (which is no longer available):
container.Kernel.ComponentModelCreated += Kernel_ComponentModelCreated;
…
void Kernel_ComponentModelCreated(Castle.Core.ComponentModel model)
{
if (model.LifestyleType == LifestyleType.Undefined)
model.LifestyleType = LifestyleType.Transient;
}
From version 5 of Windsor the accepted answer doesn't work if you are using Castle.Facilities.AspNet.SystemWeb.WebRequestScopeAccessor because the PerWebRequest lifestyle is already a scoped lifestyle.
I got it to work by changing the the ComponentModelCreated delegate to the following:
void Kernel_ComponentModelCreated(Castle.Core.ComponentModel model)
{
const string CastleScopeAccessorType = "castle.scope-accessor-type";
if (model.ExtendedProperties.Contains(CastleScopeAccessorType))
{
model.ExtendedProperties.Remove(CastleScopeAccessorType);
}
}
I ended up implementing this extension. ATTN: Must call before loading components with the PerWebRequest lifestyle:
public static class WindsorContainerExtensions
{
public static IWindsorContainer OverridePerWebRequestLifestyle(this IWindsorContainer container)
{
container.Kernel.ComponentModelCreated += model =>
{
if (model.IsPerWebRequestLifestyle())
{
model.LifestyleType = LifestyleType.Transient;
}
};
return container;
}
private static bool IsPerWebRequestLifestyle(this ComponentModel model)
{
return model.LifestyleType == LifestyleType.Scoped
&& model.HasAccessorType(typeof(WebRequestScopeAccessor));
}
private static bool HasAccessorType(this ComponentModel model, Type type)
=> model.HasExtendedProperty("castle.scope-accessor-type", type);
private static bool HasExtendedProperty<T>(this ComponentModel model, object key, T expected)
{
return model.ExtendedProperties[key] is T actual
&& EqualityComparer<T>.Default.Equals(actual, expected);
}
}
Requires these imports:
using System;
using System.Collections.Generic;
using Castle.Core;
using Castle.Facilities.AspNet.SystemWeb;
using Castle.Windsor;
If you also want to check if the type of scope is per web request you could also do this
var isPerWebRequestScope = JsonConvert.SerializeObject(model.ExtendedProperties).Contains("Castle.Facilities.AspNet.SystemWeb.WebRequestScopeAccessor")