我有一个asp.net(mvc)网站。作为函数的一部分,我将不得不支持一些长时间运行的操作,例如:
从用户发起: 用户可以将(xml)文件上传到服务器。在服务器上我需要提取文件,做一些操作(插入数据库)等...这可能需要一分钟到十分钟(甚至更多 - 取决于文件大小)。当然我不希望在导入运行时阻止请求,但我想将用户重定向到某个进度页面,在那里他将有机会观察状态,错误甚至取消导入。
此操作不会经常使用,但可能会发生两个用户同时尝试导入数据的情况。并行运行导入会很不错。一开始我想在iis中创建一个新线程(控制器动作)并在新线程中运行导入。但我不确定这是不是一个好主意(在Web服务器上创建工作线程)。我应该使用Windows服务还是其他任何方法?
从系统发起: - 我将不得不定期用新数据更新lucene索引。 - 我将不得不发送大量电子邮件(将来)。
我应该将其作为网站中的工作实现并通过Quartz.net运行工作,还是应该创建Windows服务?
运行网站“工作”时的最佳做法是什么?
谢谢!
答案 0 :(得分:6)
我会为长时间运行的任务实现独立的Windows服务。 Web应用程序通过队列方法将长时间运行的任务委托给此服务。由您决定如何组织任务队列。排队任务是否具有优先级,最大执行时间与否。队列可以作为DBMS中的普通表实现,其中包含作业执行状态信息属性(非常简单的方法)。
如此常见的情况可能如下所示:
客户端将所有必需信息发送到网络服务器
Web服务器将任务委托给服务 并通知客户 - 任务是 成功排队(任务ID也发送到客户端)
外部服务启动任务处理, 更新进度信息。
客户端开始使用以下方式轮询Web服务器 关于作业的短执行请求(之前收到的id) 现状和进展。
您可以选择不同的技术(Windows服务+ DB / WCF服务)和不同的通信方法(轮询,推送,回调),但我建议将长时间运行的任务委派给外部服务(不在Web应用程序中执行)。
执行长时间运行的任务会带来每个请求的线程模型(以多线程编程术语表示)。此模型具有较差的可伸缩性和线程池最大线程数限制。虽然这不是你的情况:)
答案 1 :(得分:4)
在我看来,长期运行的任务通常应该委托给非基于UI的操作。我建议也许是WF或Window服务。
答案 2 :(得分:1)
我使用jQuery成功实现了类似的方案。基本上,我使用beforeSend
:函数来显示“请稍候”类型页面。这是播放的基本代码(altso我不这样做,你也可以使用AsyncController
基类来使动作异步):
<script type="text/javascript">
$(document).ready(function() {
$('#create').bind('click', function() {
saveFundProperty();
});
});
// main functions
function saveFundProperty() {
var url = '<%= Url.Action("Create", "FundProperty") %>';
var params = { fundId: $("#FundID").val(), propertyId: $("#PropertyID").val() };
SendAjax(url, params, beforeQuery, saveFundPropertyResponse);
}
function beforeQuery() {
var url = '<%= Url.Action("Wait", "FundProperty") %>';
$("#statusMsg").load(url);
}
function saveFundPropertyResponse(data) {
if (data.length != 0) {
if (data.indexOf("ERROR:") >= 0) {
$("#statusMsg").html(data).css('backgroundColor','#eeaa00');
}
else {
$("#statusMsg").html(data);
}
}
}
</script>
希望这会有所帮助。
SendAjax
方法纯粹是一个包装函数,可以使事情更加一致。在这里它是完整的:
<script type="text/javascript">
function SendAjax(urlMethod, jsonData, beforeSendFunction, returnFunction, dataType, contentType) {
$.ajaxSetup({ cache: false });
dataType = dataType || "text"; // default return type
contentType = contentType || "application/x-www-form-urlencoded"; // default input type
$.ajax({
type: "POST",
url: urlMethod,
data: jsonData,
dataType: dataType,
contentType: contentType,
beforeSend: function() {
if(beforeSendFunction!==null)
beforeSendFunction();
},
success: function(data) {
// Do something interesting here.
if (data != null && returnFunction!==null) {
returnFunction(data);
}
},
error: function(xhr, status, error) {
// Boil the ASP.NET AJAX error down to JSON.
var err = eval("(" + xhr.responseText + ")");
// Display the specific error raised by the server
alert(err.Message);
}
});
}
</script>
[edit] - 不确定SendAjax格式化会发生什么。希望复制/粘贴很容易...