我在Ubuntu 16.04 LTS上运行的Asp.Net Core 1.1应用程序出现故障。
通常,在一段时间不活动后,当我点击加载网站上的某个地方触发控制器时,网站无法完成加载。我看到控制器在第一个函数15分钟后调用超时,该函数应该从数据库中获取对象(即使在连接字符串中将MySql超时设置为2分钟):
at Frontend.Repository.WebsiteSettingsRepository.Find(String id, Boolean getRelated)
at Frontend.Controllers.HomeController.Index()
这是我得到的完整例外:
fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[0]
An unhandled exception has occurred: Connect Timeout expired.
MySql.Data.MySqlClient.MySqlException: Connect Timeout expired. ---> System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.Socket'.
at System.Net.Sockets.Socket.BeginConnect(IPAddress address, Int32 port, AsyncCallback requestCallback, Object state)
at System.Net.Sockets.TcpClient.BeginConnect(IPAddress address, Int32 port, AsyncCallback requestCallback, Object state)
at System.Threading.Tasks.TaskFactory`1.FromAsyncImpl[TArg1,TArg2](Func`5 beginMethod, Func`2 endFunction, Action`1 endAction, TArg1 arg1, TArg2 arg2, Object state, TaskCreationOptions creationOptions)
at System.Net.Sockets.TcpClient.ConnectAsync(IPAddress address, Int32 port)
at MySql.Data.Serialization.MySqlSession.<OpenTcpSocketAsync>d__30.MoveNext()
--- End of inner exception stack trace ---
at MySql.Data.Serialization.MySqlSession.<OpenTcpSocketAsync>d__30.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at MySql.Data.Serialization.MySqlSession.<ConnectAsync>d__22.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at MySql.Data.MySqlClient.ConnectionPool.<GetSessionAsync>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at MySql.Data.MySqlClient.MySqlConnection.<CreateSessionAsync>d__57.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at MySql.Data.MySqlClient.MySqlConnection.<OpenAsync>d__11.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at MySql.Data.MySqlClient.MySqlConnection.Open()
at Microsoft.EntityFrameworkCore.Storage.Internal.MySqlRelationalConnection.Open()
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable.Enumerator.BufferlessMoveNext(Boolean buffer)
at Microsoft.EntityFrameworkCore.Query.QueryMethodProvider.<_ShapedQuery>d__3`1.MoveNext()
at Microsoft.EntityFrameworkCore.Query.Internal.MySqlQueryingEnumerable`1.MySqlEnumerator.MoveNext()
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
at lambda_method(Closure , QueryContext )
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass20_0`1.<CompileQueryCore>b__0(QueryContext qc)
at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)
at Frontend.Repository.WebsiteSettingsRepository.Find(String id, Boolean getRelated)
at Frontend.Controllers.HomeController.Index()
at lambda_method(Closure , Object , Object[] )
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeActionMethodAsync>d__27.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeNextActionFilterAsync>d__25.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeNextResourceFilter>d__22.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ResourceExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeAsync>d__20.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Builder.RouterMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.<Invoke>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>d__6.MoveNext()
我使用依赖注入将上下文传递给存储库:
services.AddDbContext<DatabaseConnector>(options =>
{
options.UseMySql(mysqlConfigString);
options.ConfigureWarnings(warnings => warnings.Throw(CoreEventId.IncludeIgnoredWarning));
});
在构造函数中:
public WebsiteSettingsRepository(DatabaseConnector dbContext)
{
_db = dbContext;
}
DatabaseConnector有几个DbSets,例如:
public DbSet<UserModel> Users { get; set; }
据我所知,数据库上下文还使用默认内存缓存来获取临时结果。
数据库仅用于获取前端的详细信息,因此传输的数据量很小(核心数据存储在单独的分布式群集中)。
我怀疑可能会超出池中的连接数,但这会产生不同的错误。不应该有任何连接泄漏,因为永远不会显式打开连接。现在,我认为它可能是特定于操作系统的。大多数时候网站工作正常。有任何想法吗?我已经尝试过扩展虚拟机。
[更新]
控制器的代码,它甚至不是异步的,它只使用多个存储库:
public IActionResult Index()
{
var activity = new CustomLog("HomeController.Index");
try
{
(a couple of non-db lines, the next one throws)
var newsSpeed = _settingsRepository.Find(WebsiteSetting.NewsSpeed.ToString());
(...)
if (newsSpeed != null && newsSpeed.Value != null)
{
tableConfig.NewsScrollSpeed = int.Parse(newsSpeed.Value);
}
(a lot of similar stuff there...)
return View(tableConfig);
}
catch(Exception e)
{
activity.Finish(e);
throw;
}
}
在控制器的构造函数中通过DI设置SettingRepository,如下所示:
private readonly IGenericRepositoryNamed<WebsiteSettingsModel, WebsiteSettingsViewModel> _settingsRepository;
在Startup.cs中创建:
services.AddScoped<IGenericRepositoryNamed<WebsiteSettingsModel, WebsiteSettingsViewModel>, WebsiteSettingsRepository>();