简体   繁体   English

Nhibernate,SQL Server和IIS 7.5连接泄漏:从应用程序池获取连接之前超时

[英]Nhibernate, SQL Server and IIS 7.5 Connection leak : Timeout prior to obtaining a connection from the app pool

I have an MVC application deployed on 3 separate servers (Test, Staging and Production Environment). 我有一个MVC应用程序部署在3个单独的服务器(测试,暂存和生产环境)上。 Test and Staging server are doing fine but occassionally, the production server do pull this error 测试和登台服务器运行正常,但有时生产服务器会拉出此错误

System.InvalidOperationException Timeout expired. System.InvalidOperationException超时已过期。 The timeout period elapsed prior to obtaining a connection >from the pool. >从池中获取连接之前,超时时间已过去。 This may have occurred because all pooled connections were in >use and max pool size was reached. 这可能是因为所有池化连接都在使用中并且已达到最大池大小。

The full stack trace as captured by elmah is as shown below. elmah捕获的完整堆栈跟踪如下所示。

超时错误信息

The production server is on SQL Server 2008 and IIS 7.5. 生产服务器位于SQL Server 2008和IIS 7.5上。

My Nhibernate Driver connector is as shown below 我的Nhibernate驱动程序连接器如下所示

 <?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
    <property    name="dialect">NHibernate.Dialect.MsSql2008Dialect,NHibernate</property>
    <property name="adonet.batch_size">0</property>
    <property name="show_sql">true</property> 
    <mapping assembly="BusinessLogic"/>
</session-factory>
</hibernate-configuration>

Here is my Get current session Method 这是我获取当前会话的方法

 public static ISession GetCurrentSession()
        {
            HttpContext context = HttpContext.Current;
            ISession currentSession = context.Items[CURRENT_NHIBERNATE_SESSION_KEY] as ISession;

            if (currentSession == null)
            {
                currentSession = sessionFactory.OpenSession();
                context.Items[CURRENT_NHIBERNATE_SESSION_KEY] = currentSession;
            }
            if (currentSession.Connection.State == System.Data.ConnectionState.Closed)
            {
                currentSession = sessionFactory.OpenSession();
            }
            if (!currentSession.IsConnected)
            {
                currentSession = sessionFactory.OpenSession();
            }
            if (!currentSession.IsOpen)
            {
                currentSession = sessionFactory.OpenSession();
            }
            if (currentSession.IsDirty())
            {
                currentSession.Clear();
            }

            return currentSession;
        }

I used IRepository pattern for all my business logic. 我将IRepository模式用于所有业务逻辑。 One of my method is shown here: 我的方法之一显示在这里:

 public IList<CourseRequirement> getCourseRequirement(int requirementId)
            {
                ISession  session = _courseRequirment.CurrentSession;
                var cr = session.QueryOver<CourseRequirement>().Where(x => x.RequirementId == requirementId);
                return cr.List<CourseRequirement>();
            }

In addition, I am using autofac for dependency injection. 另外,我正在使用autofac进行依赖项注入。 I can also see this in the inner exception every time it happens. 每次发生时,我也可以在内部异常中看到这一点。

System.InvalidOperationException: An error occurred when trying to create a controller of type 'ASSEMBLY.Controllers.AccountController'. System.InvalidOperationException:尝试创建类型为'ASSEMBLY.Controllers.AccountController'的控制器时发生错误。 Make sure that the controller has a parameterless public constructor. 确保控制器具有无参数的公共构造函数。 ---> Autofac.Core.DependencyResolutionException: An exception was thrown while invoking the constructor 'Void .ctor()' on type 'NHibernateRepository`2'. ---> Autofac.Core.DependencyResolutionException:调用类型为'NHibernateRepository`2'的构造函数'Void .ctor()'时引发了异常。 ---> 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 and max pool size was reached. 这可能是因为所有池化连接都在使用中,并且达到了最大池大小。 (See inner exception for details.) ---> System.InvalidOperationException: Timeout expired. (有关详细信息,请参阅内部异常。)---> System.InvalidOperationException:超时已过期。 The timeout period elapsed prior to obtaining a connection from the pool. 从池中获取连接之前已经过超时时间。 This may have occurred because all pooled connections were in use and max pool size was reached. 这可能是因为所有池化连接都在使用中,并且达到了最大池大小。

What I have done 我做了什么

I have checked these link , link and many more. 我检查了这些链接链接等等。 Others like how-to-fix-sql-connection-leaks-in-this-code suggested putting the sql in using statements. 其他类似“ 如何在此代码中修复SQL连接泄漏”的建议将sql放入using语句中。 Almost, all the links suggested connection leak in the application and recommends putting all transaction in a using statement. 几乎所有链接建议应用程序中的连接泄漏,并建议将所有事务放入using语句中。

Implement that implies rewriting most methods in my business logic. 实现意味着要重写我的业务逻辑中的大多数方法。

I am worried because this is not the only application I have written this way and besides Test and staging environment are fine. 我很担心,因为这不是我用这种方式编写的唯一应用程序,而且测试和暂存环境还不错。 From logging report, this often happens when the site is on low traffic eg 6:00 am, 3.00 am but the time is not fixed. 从日志报告中,这通常发生在站点流量较低时,例如6:00 am,3.00 am,但时间不固定。

Kindly help 请帮助

Update This is my autofac Dependency resolver(I can see from the inner exception that autofac could not instantiate some services occasionally 更新这是我的autofac依赖关系解析器(我从内部异常中可以看到autofac有时无法实例化某些服务

 public class FormDependencyResolver
    {
        public static void RegisterDependencies()
        {

            var builder = new ContainerBuilder();

            builder.RegisterControllers(typeof(MvcApplication).Assembly);


            builder.Register(c =>
                //register FakeHttpContext when HttpContext is not available
                HttpContext.Current != null ?
                (new HttpContextWrapper(HttpContext.Current) as HttpContextBase) :
                (new FakeHttpContext("~/") as HttpContextBase))
                .As<HttpContextBase>()
                .InstancePerLifetimeScope();
            builder.Register(c => c.Resolve<HttpContextBase>().Request)
                .As<HttpRequestBase>().InstancePerLifetimeScope();

            builder.Register(c => c.Resolve<HttpContextBase>().Response)
                .As<HttpResponseBase>()
                .InstancePerLifetimeScope();
            builder.Register(c => c.Resolve<HttpContextBase>().Server)
                .As<HttpServerUtilityBase>()
                .InstancePerLifetimeScope();
            builder.Register(c => c.Resolve<HttpContextBase>().Session)
                .As<HttpSessionStateBase>()
                .InstancePerLifetimeScope();



            builder.RegisterGeneric(typeof(NHibernateRepository<,>)).As(typeof(IRepository<,>)).InstancePerLifetimeScope();
            builder.RegisterType<AsyncService>().As<IAsyncService>().InstancePerLifetimeScope();//.InstancePerLifetimeScope();
            builder.RegisterType<SMSSender>().As<ISMSSender>().InstancePerLifetimeScope();
            builder.RegisterType<SMSAccount>().As<ISMSAccount>().InstancePerLifetimeScope();
            builder.RegisterType<BusinessLogic.Services.AuthenticationService>().As<IAuthenticationService>().InstancePerLifetimeScope();
            builder.RegisterType<PageHelper>().As<IPageHelper>().InstancePerLifetimeScope();

            builder.RegisterType<UtilityService>().As<IUtilityService>().InstancePerLifetimeScope();
            builder.RegisterType<WebWorker>().As<IWebWorker>().InstancePerLifetimeScope();
            builder.RegisterType<DateTimeHelper>().As<IDateTimeHelper>().InstancePerLifetimeScope();
            builder.RegisterType<UserService>().As<IUserService>().InstancePerLifetimeScope();
            builder.RegisterType<AuditService>().As<IAuditService>().InstancePerLifetimeScope();
            builder.RegisterType<HtmlHelper>().InstancePerDependency();
            builder.RegisterType<PaymentService>().As<IPaymentService>().InstancePerLifetimeScope();

            IContainer container = builder.Build();
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

        }
    }

You are opening new session instances in each of those if statements. 您将在每个这些if语句中打开新的会话实例。 Several of them can be executed at once because there are not else statements. 因为没有else语句,所以可以一次执行其中的几个。 The previously opened session would go out of scope without calling Dispose() . 先前打开的会话将超出范围,而无需调用Dispose()

The code below is everything you should need. 下面的代码是您需要的一切。 Just make sure to dispose the session instance at the end of the HTTP request. 只需确保将会话实例放在HTTP请求的末尾即可。

private static readonly object syncObject = new Object();

public static ISession GetCurrentSession()
{   
     lock (syncObject)
     {
         HttpContext context = HttpContext.Current;
         ISession currentSession = context.Items[CURRENT_NHIBERNATE_SESSION_KEY] as ISession;

         if (currentSession == null)
         {
             currentSession = sessionFactory.OpenSession();
         }

         context.Items[CURRENT_NHIBERNATE_SESSION_KEY] = currentSession;    

         return currentSession;
     }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 连接泄漏是否会导致Timeout过期。 从池中获取连接之前是否已经过了超时时间? - Will connection leak might Cause Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool? ASP - 从池中获取连接之前经过的超时时间 - ASP - the timeout period elapsed prior to obtaining a connection from the pool 从池中获取连接之前经过的超时时间 - The timeout period elapsed prior to obtaining a connection from pool 如何修复“从池中获取连接之前已过超时时间” - How to fix “Timeout period elapsed prior to obtaining a connection from the pool” 从池中获取连接之前经过的超时时间 - The timeout period elapsed prior to obtaining a connection from the pool MySqlException:从池中获取连接之前经过了超时时间 - MySqlException: The timeout period elapsed prior to obtaining a connection from the pool SqlConnection-从池中获取连接之前经过的超时时间 - SqlConnection - The timeout period elapsed prior to obtaining a connection from the pool C# 连接池问题:从池中获取连接之前超时时间已过 - C# Connection pool issue: The timeout period elapsed prior to obtaining a connection from the pool 获取异常超时已过期。 从池中获取连接之前经过的超时时间 - Getting exception Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool 超时已过。 在从池中获取连接之前超时时间已过。 - Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool.
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM