0

I am developing a web services project using the ServiceStack framework. I would like to create a global object(in my case, a SessionManager object for a GDS system I am working against, it has no relation to ASP.NET sessions) to be accessed by all incoming requests.

However, I am facing a problem whereby ASP.NET will create a new instance of my application and thereby create a new instance of my SessionManager a few times in it's life cycle. I verified this by putting a debugging line on Application_Start and Application_End protected methods in the Global.asax class and realized that the Global.asax class starts and end a number of times in its life cycle. I tried declaring my SessionManager in a static class and used it via a static construct but it still creates new instances of my SessionManager. Not sure why.

So my question is how can I create a proper global (in memory) object that can be access by all requests?

Initially I thought that by using the IoC container and specifying its singleton scope that I could achieve a singleton object, but it doesn't seems like this is the case in the ASP.NET world. So please pardon me for my knowledge in the ASP.NET area as i come from a front end development background. Hope to gain some knowledge in this area from some of the experts in this community. May thanks in advance!

icube
  • 2,578
  • 1
  • 30
  • 63

3 Answers3

2

I am facing a problem whereby ASP.NET will create a new instance of my application and thereby create a new instance of my SessionManager a few times in it's life cycle. I verified this by putting a debugging line on Application_Start and Application_End protected methods in the Global.asax class and realized that the Global.asax class starts and end a number of times in its life cycle.

IIS Application Pool Recycling:

What you are seeing here is IIS recycling the application pool. IIS does this to try and prevent memory leaks. You can configure the recycling to occur at specific intervals.

I tried declaring my SessionManager in a static class and used it via a static construct but it still creates new instances of my SessionManager. Not sure why.

Unfortunately static variables don't survive recycling, so if your application is recycled you have to create a new instance of your SessionManager class. Which means you will need to handle persisting and restoring its state across application instances.

By default the recycling process uses an overlapped mechanism, whereby it starts an new instance of your application before terminating the old instance. This means there is no downtime to users while the application instance is shutdown and started. Unfortunately this means that you can't save the state of SessionManager in Application_End and restore it in Application_Start in the new instance because Application_End of the current instance will be called after the other application is up and running. So if you were going to do it that way, you would need to disable overlapping. But remember if you disable overlapping, there may be a small downtime then while the recycling occurs.

This article explains the recycling and the considerations.

How I would handle this:

  • Disable application pool recycling overlapping
  • Create a static instance of SessionManager that is created once when the application starts, in Application_Start.
  • In Application_End save the state of SessionManager to persistent storage so it can be restored in the same state when initialised in Application_Start. Perhaps serialise the state of JSON or XML.

Initially I thought that by using the IoC container and specifying its singleton scope that I could achieve a singleton object, but it doesn't seems like this is the case in the ASP.NET world.

Once you have solved the recycling issues, you don't need to use IoC to access the static object in ServiceStack as long as it is in global scope.


Maintaining the interval schedule after application restart

I have two solutions to maintaining the interval schedule. Solution 1, is simple and requires no external dependencies, though it does require to persist a date value, but this could be to a simple text file. Solution 2, is generic in that most platforms have support for it, with little configuration.

  1. I would use a timer to run the event every 10 minutes, then record the time of the last successful check of the sessions in persistent storage (i.e. a text file, database or external cache). Then if your application is restarted, when it starts up simply determine how long it should be until the next check. This will mean that IIS application pool recycling restarts shouldn't effect the interval.

    Pseudo Code:

    const int interval = 10; // Run every 10 minutes
    double timerInverval = 60 * interval; // In seconds
    
    // Get last run from peristent storage
    DateTime? lastRun = GetLastRunTime(); // Substitute with appropriate call from storage
    
    // Determine elapsed time
    if(lastRun.HasValue) {
        var secondsRemainingUntilNextRun = (lastRun.Value.AddMinutes(interval) - DateTime.Now).TotalSeconds;
        if(secondsRemainingUntilNextRun <= 0){
            // Run immediately, the web application has been down and missed running the SessionManager job
            SessionManager.CheckSessions(); // Substitute with appropriate call
        } else {
            timerInterval = secondsRemainingUntilNextRun;
        }
    }
    
    // Set a timer to trigger the SessionManager job after timerInterval seconds
    timer.interval = timerInterval;
    
  2. Alternatively you could create a scheduled task that calls your web application and triggers this action. If the task is triggered independently of the web application, then it doesn't have to worry about maintaining the schedule if the application is restarted. I believe Azure has a scheduler service, or if you run a cloud instance then you can create a system scheduled task.

Scott
  • 21,211
  • 8
  • 65
  • 72
  • Application pool recycling is there for a reason. Performance. You don't want to end up with a long-running w3wp process. http://stackoverflow.com/questions/7171367/why-do-iis-application-pools-need-to-be-recycled – Adrian Salazar Mar 03 '14 at 16:29
  • @AdrianSalazar I never said to not recycle the application. I simply suggested disabling the overlapping to make the saving and restoration of state easier. I will however make it clearer that they should continue to allow recycling frequently. – Scott Mar 03 '14 at 16:38
  • thanks for the suggestion but i'm not sure if i should go this route because my SessionManager is scheduled to run a scan/check on all the sessions in the pool to the GDS at 10 mins interval to refresh their validity. so i can't do a "pause" state for the SessionManager. any other suggestions? – icube Mar 04 '14 at 04:02
  • @icube Without knowing more about SessionManager and why you need an external process to refresh session validity that is accessible to all processes it's not possible to provide a useful solution. If you can explain what is happening and why you are doing it this way then I may be able to help. – Scott Mar 04 '14 at 09:49
  • @Scott one objective of the SessionManager is to maintain high availability of valid sessions for use for the web services. Whenever a web service request is requested, the SessionManager is there to handout the sessions immediately. The sticky point with these sessions is that there is an expiry time for each session and one of the role of the SessionManager is to refresh/validate it. This is by design by the GDS I am working on. The GDS documentation recommends we have a SessionManager to handle sessions in the event of heavy load of incoming requests. – icube Mar 04 '14 at 10:31
  • @icube Thanks for the info, this makes it clearer. Unfortunately the memory of the web application is volatile to IIS application recycling as I explained. As you are trying to maintain high availability, storing session data in the memory of the application **will never allow high availability**, because the application can be terminated at any time. Handling session data under heavy load and maintaining high availability must be maintained by services outside of the application such as Redis, memcached or [Azure Cache](http://www.windowsazure.com/en-us/services/cache/). – Scott Mar 04 '14 at 10:47
  • @icube You can still create a single static object to access the data globally from within your application, that simply uses the session data from the external data store, instead of the web application memory. But the point is, that because the data store is external to your application memory it is no longer volatile to your application restarts. – Scott Mar 04 '14 at 10:50
  • Thanks for ur answer. However i still have one unresolved puzzle. How would I implement the interval scheduling problem? Quartz.net? Or using the asp.net expire callback trick? My goal is to avoid dependency to IIS or windows service configurations if possible – icube Mar 04 '14 at 12:59
  • @icube I have updated my answer to include solutions for maintaining the interval when the application is restarted. Let me know if this helps. – Scott Mar 04 '14 at 13:57
  • @icube Did the my suggestion resolve the interval scheduling problem you were facing? Feedback is appreciated thanks. – Scott Mar 06 '14 at 16:15
  • @Scott Yup i was testing out my implementation for a day and see if there were still any problems. So, I added a Azure Scheduler service which calls my web service periodically to do the refresh on the sessions. As for the storage, I persisted them in my database because I want to be able to monitor them. Not sure whether caching can do that too? Not familiar in that space yet. So far, it seems that everything is working as I planned out. Thanks once again Scott! It's people like you that make my world a better place. Ha. If you happen to stop by Singapore, let me show you around ya. – icube Mar 07 '14 at 02:06
  • @icube Sorry for not getting back to you sooner. Hope your solution is still running smoothly now. You can still monitor a cache, but if you are finding no latency issues while using a database, then it's best to stick with it. A cache is typically more expensive because it is backed by RAM not hard disk space, so if you are surviving on DB, I would stick with that. Besides cache doesn't typically persist data for long, but with the database you can. You're welcome, glad to have helped. Thanks I haven't been to Singapore yet, one day. Please remember to accept the answer if it helps. – Scott Mar 11 '14 at 12:51
1

Your requirements are contradicting: you want in-memory store and you want it to be reliable and persistent and survive IIS application pool recycles. The system memory just isn't such a reliable store. If you need some persistent data you should consider using what is designed for this purpose: a database or even a file on the hard drive for example.

And of course to optimize the performance you could use an in-memory caching layer to avoid hitting your persistent layer every time you need to access the information. Another advantage to using a persistent store is that if your application is hosted in a webfarm across multiple nodes, all those nodes will be able to share the same data.

Just don't rely on IIS recycling. No matter what options you are tweaking in the IIS console, the AppPool might someday simply die wiping everything you have stored in memory and there's nothing you could do about it.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • thank you for your answer and the information about IIS recycling. I didn't know such a "feature/issue" exist in ASP.NET. I will try to rethink my implementation... thanks! – icube Mar 04 '14 at 04:46
-1

ServiceStack supports redis out of the box, as well as several other caching providers: Memcached, Azure, Disk... so the choice of where to locate your global session provider is still up to you!

You should combine caching mechanism and the singleton pattern. So you define a class that has access to the underlying cache provider, all request have once single entry point to your session manager, and use this cache provider as your data repository.

It will survive recycling, crashes and it will make your life easy, once you have to scale your application.

Adrian Salazar
  • 5,279
  • 34
  • 51