我有一个数据处理MVC应用程序,可以处理从100MB到2GB的上传文件大小,并包含几个长时间运行的操作。用户将上传文件,这些文件中的数据将被处理,最后对数据的一些分析将发送给相关用户/客户。
处理数据至少需要几个小时,因此为了确保用户不必一直等待,我已经完成了一项单独的任务来完成这项任务。运行操作。这样,一旦文件被服务器接收并存储在磁盘上,用户就会得到一个带有ReferenceID的响应,他们可以关闭浏览器。
到目前为止,它已按预期运行良好但在阅读了有关在MVC中使用Fire-and-Forget模式以及在回收期间被IIS抛弃的工作线程的问题后,我对这种方法感到担忧。
这种方法仍然安全吗?如果没有,我如何确保处理数据的线程在完成处理并将数据发送给客户端之前不会消亡? (以相对简单的方式)
该应用程序在.NET 4.5上运行,所以不要认为我现在可以使用HostingEnvironment.QueueBackgroundWorkItem
。
在控制器帮助下使用Async / Await吗?
我还想过在应用服务器上使用消息队列来存储消息,一旦文件存储到磁盘,然后使DataProcessor成为一个单独的服务/进程,然后监听队列。如果队列是可恢复的,那么它将确保即使服务器崩溃或线程在完成数据处理之前被丢弃,也将始终最终处理消息。这是一种更好的方法吗?
我目前的设置如下所示
控制器
public ActionResult ProcessFiles()
{
HttpFileCollectionBase uploadedfiles = Request.Files;
var isValid = ValidateService.ValidateFiles(uploadedFiles);
if(!isValid){
return View("Error");
}
var referenceId = DataProcessor.ProcessData(uploadedFiles);
return View(referenceId);
}
业务逻辑
public Class DataProcessor
{
public int ProcessFiles(HttpFileCollectionBase uploadedFiles)
{
var referenceId = GetUniqueReferenceIdForCurrentSession();
var location = SaveIncomingFilesToDisk(referenceId, uploadedFiles);
//ProcessData makes a DB call and takes a few hours to complete.
TaskFactory.StartNew(() => ProcessData(ReferenceId,location))
.ContinueWith((prevTask) =>
{
Log.Info("Completed Processing. Carrying on with other work");
//Below method takes about 30 mins to an hour
SendDataToRelatedClients(ReferenceId);
}
return referenceId;
}
}
参考
http://blog.stephencleary.com/2014/06/fire-and-forget-on-asp-net.html
答案 0 :(得分:5)
这种做法是否仍然安全?
从来没有安全。
在控制器帮助下使用Async / Await吗?
没有
该应用程序在.NET 4.5上运行,所以不要认为我现在可以使用HostingEnvironment.QueueBackgroundWorkItem。
我有AspNetBackgroundTasks library基本上与QueueBackgroundWorkItem
做同样的事情(略有不同)。然而...
我还想过在应用服务器上使用消息队列来存储消息,一旦文件存储到磁盘,然后使DataProcessor成为一个单独的服务/进程,然后监听队列。如果队列是可恢复的,那么它将确保即使服务器崩溃或线程在完成数据处理之前被丢弃,也将始终最终处理消息。这是一种更好的方法吗?
是。这是唯一可靠的方法。这就是我称之为'#34;正确的分布式架构"在my blog post。
答案 1 :(得分:0)
不,这不安全。在服务器上创建一个处理这些请求的服务应用程序并发布结果。如果您在Azure上托管,请使用他们的WebJob服务。