【问题标题】:ASP.NET long running task. Thread is being aborted exceptionASP.NET 长时间运行的任务。线程被中止异常
【发布时间】:2013-04-21 16:45:00
【问题描述】:

一个 ASP.NET 3.5 webapp 必须启动几个需要几个小时才能完成的任务。由于显而易见的原因,启动这些任务的页面不能等待它们完成,也不会有人希望等待那么长时间才能获得响应,因此这些任务必须是异步的。

有一个 Helper 类来处理所有这些长时间运行的任务。目前调度和执行这些任务的主要方法如下:

public static bool ScheduleTask(TaskDescriptor task, Action action)
{
    bool notAlreadyRunning = TasksAsync.TryAdd(task);
    if (notAlreadyRunning)
    {
        Thread worker = null;
        worker = new Thread(() => 
        {
            try { action(); }
            catch(Exception e)
            {
                Log.LogException(e, "Worker");
            }
            TasksAsync.RemoveTask(task);
            workers.Remove(worker);
        });
        workers.Add(worker);
        worker.Start();
    }
    return notAlreadyRunning;
}

在早期的实现中,我们使用了ThreadPool.QueueUserWorkItem 方法,但结果始终相同:在 aprox. 20-30 分钟 Thread was being aborted 抛出异常。

有谁知道为什么会这样?或者如何预防?

更多信息:

  • IIS 标准配置。
  • 任务可以是任何东西,对数据库的查询和/或 IO 操作等。

更新:决定

感谢大家的回复。现在我不知道将哪个问题标记为答案。所有这些都是有效的,并且是解决此问题的可能方法。将等待今天并将投票最多的答案标记为答案,如果出现平局,我将选择第一个显示的答案,通常它们按最相关性排序。

对于任何想知道我选择的解决方案的人,同样由于时间限制,是更改 IIS 回收配置,但根据我的研究,当然还有下面的答案,我认为这是理想的解决方案,就是创建一个“Worker Service”,并使用 ASP.NET App 和新的“Worker Service”之间的通信解决方案来协调要完成的长时间运行的工作。

【问题讨论】:

  • 您的 IIS AppPools/workers 是否回收?
  • IIS 配置是 IIS 7 的标准配置。所以是的,我猜。
  • 我已经有一段时间没有深入了解 ASP.NET,但是如果内存可用,当工作进程回收时,它们可以停止线程。尝试禁用回收,看看这是否是线程中止的根源。 (如果是这种情况,不确定是否有解决方法;就像我说的,没有触及 那个 特定问题)
  • Phill Haack 在他的The Dangers of Implementing Recurring Background Tasks In ASP.NET 帖子中深入探讨了这个主题。希望对你有帮助
  • 您可以按照以下线程禁用应用程序池回收:stackoverflow.com/questions/3156925/…,但我认为最好的方法是按照 Robert 的建议在不同的应用程序域上运行它。

标签: c# asp.net asynchronous


【解决方案1】:

您可以在其自己的应用程序域中启动长时间运行的进程。

过去,当我需要此功能时,我会为此创建一个 Windows 服务。如果使用 WCF 连接它,它甚至根本不必在 IIS 机器上运行;你可以在网络上的任何机器上运行它。

【讨论】:

  • 我认为你是对的,这将是采取的方法,但由于时间限制,我认为我们无法做到。
  • 我认为你真的别无选择。 Phil Haack 非常清楚地表明 IIS 并非设计用于执行此操作。您可以尝试在新的应用程序域中启动线程:pcreview.co.uk/forums/start-thread-new-appdomain-t3614317.html
  • 我不知道你可以像那样动态地创建一个应用程序域……我想我会读到的。但是,如果您可以为我节省一点研究,那么当线程结束时,appdomain 会发生什么?基本上我如何确保释放新 appdomain 的资源?
  • 回到“过去”,我们使用 COM+ 和 MSMQ 来执行这种长时间运行的过程。我认为这里的 WCF 和基于服务的建议应该可以正常工作。如果您愿意,您可能仍然可以使用 MSMQ。
  • @jfrankcarr:使用 .NET Remoting 很容易做到,但无论出于何种原因,该技术已不再流行。 WCF 是新的黑色。
【解决方案2】:

您可以通过增加超时、使用不同的应用程序池或各种其他 hack 来实现此功能,但最好的办法是将长期运行的任务与 ui 和 asp.net 完全分离,并使用服务(不推荐)或轮询工作的计划任务;我个人会使用 aws sqs/sns 之类的东西来跟踪要完成的工作和 Windows 服务器中的计划任务,以任何有意义的频率检查待办事项。 ui/asp.net 唯一需要做的就是记录需要做某事的事实,而不是实际去做。

这种基于消息的方法的另一个好处是,如果长时间运行的进程运行时间过长或工作过度,您将有机会添加更多工作任务或服务器来完成这些请求。

对于当前的问题,可能比您可以实施的更多,但需要考虑一些事情以获得更好的长期解决方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-13
    • 1970-01-01
    • 2012-08-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多