【发布时间】:2012-12-10 19:43:09
【问题描述】:
我有一个从 ASP.NET MVC4 网页启动的长时间运行的异步任务。控制器方法如下所示:
[HttpPost]
public ActionResult Index(IndexModel model)
{
if (ModelState.IsValid)
{
try
{
model.NotificationRecipient = model.NotificationRecipient.Replace(';', ',');
ImportConfiguration config = new ImportConfiguration()
{
BatchId = model.BatchId,
ReportRecipients = model.NotificationRecipient.Split(',').Select(c => c.Trim())
};
System.Threading.ThreadPool.QueueUserWorkItem(foo => LaunchFileImporter(config, this.HttpContext.ApplicationInstance.Context));
if (model.RunExport) ThreadPool.QueueUserWorkItem(foo => LaunchFileExporter());
Log.InfoFormat("Queued the ImportProcessor to process invoices. Send Notification: {0} Email Recipient: {1}",
model.SendNotification, model.NotificationRecipient);
TempData["message"] = "The import processor job has been started.";
//return RedirectToAction("Index", "Home");
}
catch (Exception ex)
{
Log.Error("Failed to properly queue the invoice import job.", ex);
ModelState.AddModelError("", ex.Message);
}
}
var dirInfo = new System.IO.DirectoryInfo(dir);
model.Files = dirInfo.EnumerateFiles("*.xml").OrderBy(x => x.Name.ToLower());
return View(model);
}
我的LaunchFileImporter 方法如下所示:
private void LaunchFileImporter(ImportConfiguration config, System.Web.HttpContext context)
{
//the semaphore prevents concurrent running of this process, which can cause contention.
Log.Trace(t => t("submitter semaphore: {0}", (exporter == null) ? "NULL" : "present."));
submitter.WaitOne();
try
{
Log.Trace(t => t("Context: {0}", context));
using (var processor = new ImportProcessor(context))
{
processor.OnFileProcessed += new InvoiceFileProcessing(InvoiceFileProcessingHandler);
processor.OnInvoiceProcessed += new InvoiceSubmitted(InvoiceSubmittedHandler);
processor.Execute(config);
}
}
catch (Exception ex)
{
Log.Error("Failed in execution of the File Importer.", ex);
}
submitter.Release();
}
我的 Logger 是 Common.Logging private static readonly ILog,并为 NLog 配置。似乎接线正确;至少,我从中得到了相当多的日志。
事情是这样的:在我点击System.Threading.ThreadPool.QueueUserWorkItem 的那一刻,应用程序池死亡螺旋变成了无声的死亡,重置应用程序池,重新加载会员提供程序,重新处理 web.config,整个 shebang……没有 YSOD,网页上没有任何指示……一切都悄悄地爆炸了。我得到的最后一个日志条目是Queued the ImportProcessor to process invoices...。
我应该注意页面会刷新。 TempData["message"] 被填充并显示在屏幕上,这让我相信问题发生在异步过程中......但几乎是立即发生的。由于缺少其他日志,我假设记录器存在问题。
所以我希望有人可以告诉我发生了什么,指出一些记录在案的问题,告诉我我是如何成为一个白痴,或者重现类似的错误。
谢谢!
更新
@RichardDeeming 指出上下文信息没有进入生成的线程,这似乎是问题的原因。我还没有弄清楚为什么这不起作用,也没有写跟踪消息,但是一旦我捕获了我需要的上下文部分IPrincipal,并使用它而不是上下文对象,它刚刚工作。
【问题讨论】:
-
长时间运行的异步任务和 ASP.NET 是一个非常糟糕的组合......
-
嗯...我一般同意。在这种情况下,某些情况使其成为最佳选择。
-
在 IIS 中使用额外的后台线程可能会影响 IIS 性能...另一点是,由于任何原因(如内存压力等),IIS 可以随时重新加载您的 appdomain(有一些配置选项)。如果您的 appdomain 负载过重,上述情况可能只是 IIS 中“硬重新加载”的症状......
-
您可能会在
foo => LaunchFileImporter(config, this.HttpContext.ApplicationInstance.Context)线上获得NullReferenceException- 我很确定Context在请求完成后会被清理。正如我们所知,后台线程上未处理的异常会导致整个AppDomain崩溃。 -
此应用程序仅由一个人在任何时候使用。对于我们位于美国另一端的办公室的 A/P 部门来说,这实际上只是一个“按下按钮”,以启动过去每天一次的高度手动流程,所以我相信服务器不是在高负载下。我真的认为这里的重点是跟踪日志没有记录在日志文件中,它甚至在进程执行之前就开始了。
标签: c# asp.net-mvc iis crash nlog