我正在使用 mean stack 开发一个Web应用程序,它可以在几个mongo db集合上执行多个操作。
系统的目的是在几个系统之间执行数据同步。每个系统数据都存储在不同的集合中。不用说,这些集合的文档具有共同的属性。
在 nodeJS 或API级别,我创建了get和post请求,这些请求将异步循环遍历主集合,并尝试将该集合上的文档与其他集合中的文档相链接。当然这个过程需要几分钟。
可以链接的文档存储在不同的mongodb集合中。稍后将在另一个节点js API调用中处理这些。
设置API后,我正在创建一个控制器和一个带角度的服务,以便连接到api并执行api get和post请求。
当我在UI中点击按钮执行此链接操作时,操作开始而不会阻止浏览器,但最终浏览器获得 ERR_EMPTY_RESPONSE ,因为操作仍然是因此我从未真正打电话给response.end()
。
我认为可能是一种可能的解决方案:
在后台长时间运行操作完成之前,我该怎么办才能避免浏览器关闭连接?
代码:
HTML - >用户单击以开始链接记录的按钮:
<div>
<md-button aria-label="link all records" ng-click="vm.linkRecords()">
<md-icon class="mdi mdi-plus"></md-icon>Link Records
</md-button>
</div>
控制器:canLink,canGrade都是布尔变量,这样当服务器进行一次操作时,其他操作都无法执行。一旦操作完成,它将返回true并允许所有操作。
function linkRecords() {
$state.go('app.records.link');
}// END linkRecords page
$scope.$on('linkRecords', function(event, batchSize){
if ( canLink && canGrade) {
showToast("Started linking records");
canLink = 0;
canGrade = 0;
recordService.linkRecords(batchSize).then(function(finished){
canLink = finished;
canGrade = finished;
});
}else if ( !canLink ){
showToast('Cannot link records: - Currently undergoing grading records');
}else if ( !canGrade ){
showToast('Cannot link records: - Currently undergoing linking records');
}
});//END linkingRecords
服务
function linkRecords(batchSize){
return $http.get(urlRoot+'/link/:'+batchSize);
}//END linkRecords
节点js api:
routes.js:
//link all records
app.post('/link/:batchSize', function(req, res){
var batchSize = req.params.batchSize;
functions.linkRecords(batchSize, function(callback){
res.end(true);
});
});//END linkRecords
functions.js:
linkRecords : function(batchSize, callback){
//link all records in all collections a batchsize at a time
async.parallel([
function(callback){
...open cursor for collection1 and loops over the collections to stitch with other collections.
},
function(callback){
...open cursor for collection2 and loops over the collections to stitch with other collections.
}
], function done(err, result){
callback();
});
}
答案 0 :(得分:0)
听起来您需要一个更强大的后端基础架构来管理和跟踪这些长时间运行的任务。如果你知道这些操作将花费很长时间&#34;这可能是几秒钟,几分钟或更长时间,那么你必须设置某种类型的队列服务来运行这些任务,跟踪它们,并处理错误情况。
API服务器的唯一责任应该是:
可以为此流程实施的一组可能的API:
POST /api/links - create a new link process
GET /api/links - display all currently running link processes
GET /api/links/:id - display a single link process
DELETE /api/links/:id - delete (or cancel) a running link process, if needed
您可以使用多种不同的队列技术来管理长时间运行的任务。如果您在AWS环境中,则可以使用SQS queues。如果您的流程涉及多个步骤,您可以查看处理数据(或流程)管道的系统。 Luigi(来自spotify开源)是一个示例服务,可用于处理非常简单(即一步)的管道,直到具有大量步骤和依赖性的极其复杂的管道。
Here is a tutorial分解了长时间运行的进程的问题,然后讨论了一些可能的实现。
答案 1 :(得分:0)
我不是MEAN堆栈的专家(但是)但我想你设计服务的方式不对。它将返回一个承诺(结果未完成),并在承诺完成之前调用结束。
尝试设计你的服务,并且route.js调用这样的东西。
<强>服务强>
angular.module('rugCoPro').factory('appraisalSearch', ['$resource', 'RugSession', function($resource, RugSession) {
return $resource("/:org/api/models/appraisals/:func/:value", { org: "@org", func: "@func", value: "@value" }, {
query: {
method: 'GET',
isArray: true,
headers: { 'Content-Type': 'application/json', 'X-Auth-Token': authToken }
}
});
}])
拨打强>
appraisalSearch(RugSession.getAuthToken()).query({ org: org, func: "multi", value: orderNumber[0] }).$promise.then(function(data) {
//success
}, function(error) {
//error
})
答案 2 :(得分:0)
我会依靠Mikelax的回答来使用队列系统来管理。我一直在使用agenda来处理我一直在研究的项目中的更长进程。
我认为值得一提(可能是 ERR_EMPTY_RESPONSE 错误的根源),Express的默认超时时间为2分钟。因此,如果您的进程需要几分钟,则应修改端点上的超时以处理请求。
您可以通过几种不同的方式修改超时,还有中间件,例如connect-timeout。您还可以通过env对象或直接在server.js文件中设置超时。