MVC - 并行任务中的 System.Threading.ThreadAbortException

use*_*260 4 .net c# asp.net-mvc multithreading entity-framework

在我的 MVC 应用程序中,超级管理员可以设置任务队列,例如更新数据库。因此,当管理员向队列添加更新时,控制器会启动一个在后台工作的新任务。但是,当您添加一些任务时,应用程序会抛出 System.Threading.ThreadAbortException: Thread was being aborted. 此外,堆栈跟踪表明它发生在代码的不同行上。

我还应该补充一点,这些任务使用 EF6 实体与 SQL-server 一起工作,并且根据堆栈跟踪,它发生在对数据库执行操作之后或期间。由于更新通常很大,我db.Configuration.AutoDetectChangesEnabled = false每 20k 行使用并手动保存更改,处理和重新创建数据库。

堆栈跟踪示例:

2015 年 7 月 15 日星期三下午 5:18:36:[报告] 异常(行:456667;第 6 节):System.Threading.ThreadAbortException:线程被中止。在 System.Array.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length, Boolean 可靠) 在 System.Collections.Generic.List`1.set_Capacity(Int32 value) 在 System.Data.Entity.Core。 Metadata.Edm.MetadataCollection`1.SetReadOnly() 在 System.Data.Entity.Core.Metadata.Edm.TypeUsage..ctor(EdmType edmType, IEnumerable`1 facets) 在 System.Data.Entity.Core.Common.CommandTrees。 DbExpression..ctor(DbExpressionKind kind, TypeUsage type, Boolean forceNullable) 在 System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder.DbExpressionBuilder.PropertyFromMember(DbExpression 实例,EdmMember 属性,

有什么我可能做错的吗?

Vov*_*ova 5

我想这可能与 IIS 空闲状态有关。您可以尝试每隔几分钟使用来自另一个空闲线程的基于自我的请求使 IIS 运行后台线程。它将防止 IIS 中止另一个后台长时间运行的线程。每 10 分钟进行一次自我请求的方法示例:

public void KeepIisBackgroundThreadsAlive(Object stateInfo) {
    while (true) {
        var serverOwnIp = Dns.GetHostEntry(Dns.GetHostName()).AddressList.First(o => o.AddressFamily == AddressFamily.InterNetwork).ToString();
        var req = (HttpWebRequest) WebRequest.Create(new Uri("http://" + serverOwnIp));
        req.Method = "GET";
        var response = (HttpWebResponse) req.GetResponse();
        var respStream = response.GetResponseStream();
        var delay = new TimeSpan(0, 0, 10, 0);
        Thread.Sleep(delay);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后您可以使用 Global.asax.cs OnApplicationStarted 方法中的 ThreadPool.QueueUserWorkItem 方法启动此方法:

protected override void OnApplicationStarted(){
    ThreadPool.QueueUserWorkItem(KeepIisBackgroundThreadsAlive)
}
Run Code Online (Sandbox Code Playgroud)

重要更新

发现这种方式只适用于禁用IIS Application Pool的回收。仔细阅读文章的情况下,你不熟悉这个IIS的功能。请注意,您应该 100% 确定自己在做什么。

如果您在不关闭回收的情况下使用这种方法,您可能会在第一次回收发生后面临网站无法启动的严重错误。对于需要应用程序池回收的这些网站,我强烈建议将长时间运行的作业移到不依赖于 IIS 的单独服务中(如果您使用 Azure Web 角色 - 至少移到单独的工作角色实例中)。