6

I'm using the new Universal Providers from Microsoft for session in SQL Server. The old implementation of session on SQL Server required a job (running every minute) to clear expired sessions. The new one does this check and clear on every request. Since I'm actually running in SQL Azure, I don't have SQL Agent to schedule jobs, so this sounds like a reasonable way to go about it (no, I don't want to pay for Azure Cache for session).

The problem is when multiple users access the site at the same time, they're both trying to clear the same expired sessions at the same time and the second gets an optimistic concurrency exception.

System.Data.OptimisticConcurrencyException: Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
   at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
   at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
   at System.Web.Providers.DefaultSessionStateProvider.PurgeExpiredSessions()
   at System.Web.Providers.DefaultSessionStateProvider.PurgeIfNeeded()
   at System.Web.SessionState.SessionStateModule.BeginAcquireState(Object source, EventArgs e, AsyncCallback cb, Object extraData)
   at System.Web.HttpApplication.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

I'm using ELMAH for error logging, and this is showing up with some frequency. Before I try to configure ELMAH to ignore the errors, does anyone know of a way to stop the errors from happening in the first place? Is there some configuration with the new providers that I'm missing?

pnuts
  • 58,317
  • 11
  • 87
  • 139
icrf
  • 364
  • 3
  • 13
  • I am also experiencing the same problem. Have you found out how to fix this issue? The only way I can think is to decompile the code? Any suggestions – chugh97 May 01 '12 at 08:30
  • 2
    The best I can tell, Microsoft isn't really supporting these providers. The cynic in me says they're trying to drive Azure users to pay for cache. I'd love for someone to prove me wrong. In the end, we gave up on it and went back to a straight SQL Server provider. We already needed another server for scheduling other unrelated jobs, so we put the clearing expired sessions job in there, too. Sorry I don't have anything better to report. – icrf May 01 '12 at 13:13
  • Have you solved this problem? I'm running into the same issue myself. – onit Jul 18 '12 at 17:21
  • Judging from responses below, it may be fixed in an updated version (1.2, release May 31). I haven't gotten back to testing it, and it looks like I'm not going to. With the latest Azure SDK, you can run cache from your instances without paying for their specialty cache servers. It's in preview, but it appears to be working well so far. Someone else on the team here moved Session to run off Cache instead of SQL (when we're on Azure, when we're on EC2, it's back to full SQL Server). – icrf Jul 18 '12 at 22:31

3 Answers3

2

Please download the newer version of the providers which can be found here: http://www.nuget.org/packages/System.Web.Providers. We have updated the way that we clean up expired sessions to run asynchronously and to handle error conditions. Please let us know if it does not correct your issues.

  • Thanks for the update. I'll try to take a look at it later this week or early next after I finish my current project. Is there any kind of public change log available? While I moved Session away from the default providers, I am still using Membership/Roles. – icrf Jun 26 '12 at 13:02
  • I'm marking this as the solution, but I haven't tested to see if it actually fixes the problem. We've moved to Azure Caching Preview for Session, so testing this isn't feasible for me anymore. – icrf Jul 19 '12 at 16:40
  • I have the exact same issue using Sql Azure and the latest nuget June 2012 . In my case I am escaping azure co located caching because it has caused several outages due to storage failure (cache state manager) and new instances not updating dependent instances of a new ip address(azure has many unknown single points of failure). Scott, this Universal Provider package is great! Any follow up on the error though? It would seem that one of two instances in azure beats the other to PurgeExpiredSessions(). – TheDev6 Jan 29 '13 at 23:19
1

I posted a question on this at the NuGet(http://www.nuget.org/packages/System.Web.Providers), and got a very quick response from the owners. After a bit of backwards and forwards, turns out they do have a fix for this, but is going out in the next update.

There was a suggestion here, that Microsoft isnt too keen on supporting this, but my experience has been otherwise, and have always received good support.

  • By "posted a question" do you mean "contacted the owner of the package" or is there some other method for posting questions on NuGet? A lot of other Microsoft projects are on Codeplex or Google Code or Github, and they all have issue trackers and discussion systems. I couldn't find this project anywhere for open discussion. – icrf Jun 29 '12 at 19:11
1

This package has a what I would describe as a bug. The premise of out of process session state is that multiple instances might be managing session state clean up. In this case all instances are running this method...

private void PurgeExpiredSessions()
{
    using (SessionEntities entities = ModelHelper.CreateSessionEntities(this.ConnectionString))
    {
        foreach (SessionEntity entity in QueryHelper.GetExpiredSessions(entities))
        {
            entities.DeleteObject(entity);
        }
        entities.SaveChanges();
        this.LastSessionPurgeTicks = DateTime.UtcNow.Ticks;
    }
}

The problem is that one instance deletes the entities before the other(s) and entities throws the error described in the post. I asked the package authors to release the source code or fix this.. My untested text editor fix would be to add public virtual, so one could override the method or just change it too..

private void PurgeExpiredSessions()
{
    using (SessionEntities entities = ModelHelper.CreateSessionEntities(this.ConnectionString))
    {   
        var sqlCommand = @"DELETE dbo.Sessions WHERE Expires < GETUTCDATE()";
        entities.ExecuteStoreCommand(sqlCommand);
        this.LastSessionPurgeTicks = DateTime.UtcNow.Ticks;
    }
}

The package authors are really fast with a response (answered while posting this!) and today they stated that they are working on releasing the code but that they might be able to just fix this. I requested an ETA and will try to follow up here if I get one.

Great package, it just needs a little maintenance.

Proper Answer: Wait for source code release or a fix update. Or De-compile and fix it yourself (If that is consistent with the license!)

*Update the package owners are considering fixing it this week. Yeah! **Update.SOLVED!!! They evidently fixed it a while ago and I was installing the wrong package.. I was using http://nuget.org/packages/System.Web.Providers and I should have been using http://nuget.org/packages/Microsoft.AspNet.Providers/ .. It was not obvious to me which one was legacy and included in another package. They wrapped it in an empty catch..

private void PurgeExpiredSessions()
{
    try
    {
        using (SessionEntities entities = ModelHelper.CreateSessionEntities(this.ConnectionString))
        {
            foreach (SessionEntity entity in QueryHelper.GetExpiredSessions(entities))
            {
                entities.DeleteObject(entity);
            }
            entities.SaveChanges();
            this.LastSessionPurgeTicks = DateTime.UtcNow.Ticks;
        }
    }
    catch
    {
    }
}

Thank you to the package team for such quick responses and great support!!!

TheDev6
  • 882
  • 9
  • 17
  • **Update. We tried this in Azure with about 250 simultaneous users and SQL Azure gave us error messages that stated the physical machine could not accept any more connections even though we were within our allowed connection limit. My verdict is to avoid this type of session management in Azure. BTW the only reason we tried this was because our current Session State backer, Azure Caching, had too many outages. – TheDev6 Mar 14 '13 at 16:12