【发布时间】:2013-12-24 18:57:51
【问题描述】:
当然,我有一个通过 ExpressJS 在 NodeJS 上发布的网络应用程序。它使用 CouchDB 作为它的数据源。我实施了长轮询以使应用程序在所有用户之间始终保持同步。为此,我使用以下逻辑:
- 用户登录应用并通过 Express 路由向 Node 发出初始长轮询请求。
- 节点依次向 CouchDB 发出长轮询请求。
- 当 Couch 更新时,它会响应来自 Node 的请求。
- Node 最后响应浏览器。
简单。但是,正在发生的事情是,当我刷新浏览器时,它会在每五次刷新 时冻结。嗯?很奇怪。但我可以一遍又一遍地重现它,即使在我的测试环境中也是如此。每第五次刷新都会冻结 Node 并导致应用程序冻结。重启节点解决了这个问题。
在拉了很多头发之后,我想到我通过改变这个来解决它:
app.get('/_changes/:since*', security, routes.changes);
到这里:
app.get('/_changes/:since*', security, function () { routes.changes });
但是,经过进一步测试,这只是无法运行 routes.changes。所以没有实际的解决方案。任何想法为什么从 Node 长轮询 CouchDb 会做这么奇怪的事情?在第五次刷新时,我可以在我的路由代码的第一行的节点中有一个断点,它永远不会被击中。但是,在浏览器中,我可以中断对节点的请求以进行长轮询,并且它似乎消失了。就像 Node 出于某种原因不接受连接...
我应该以不同的方式接近从 Node 到 CouchDB 的长轮询吗?我正在使用 feed=longpoll,我是否应该使用 feed=continuous?如果我将 couchdb 中的 changes_timeout 调低到 5 秒,它并没有解决这个问题,但它确实更容易处理,因为冻结只持续了 5 秒。所以这似乎表明该节点无法处理几个未完成的沙发请求。也许我会尝试连续提要,看看会发生什么。
self.getChanges = function (since) {
浏览器:
$.ajax({
url: "/_changes/" + since,
type: "GET", dataType: "json", cache: false,
success: function (data) {
try {
self.processChanges(data.results);
self.lastSeq(data.last_seq);
self.getChanges(self.lastSeq());
self.longPollErrorCount(0);
} catch (e) {
self.longPollErrorCount(self.longPollErrorCount() + 1);
if (self.longPollErrorCount() < 10) {
setTimeout(function () {
self.getChanges(self.lastSeq());
}, 3000);
} else {
alert("You have lost contact with the server. Please refresh your browser.");
}
}
},
error: function (data) {
self.longPollErrorCount(self.longPollErrorCount() + 1);
if (self.longPollErrorCount() < 10) {
setTimeout(function () {
self.getChanges(self.lastSeq());
}, 3000);
} else {
alert("You have lost contact with the server. Please refresh your browser.");
}
}
});
}
节点:
路由:
exports.changes = function (req, res) {
var args = {};
args.since = req.params.since;
db.changes(args, function (err, body, headers) {
if (err) {
console.log("Error retrieving changes feed: "+err);
res.send(err.status_code);
} else {
//send my response... code removed here
}
})
}
数据库长轮询调用:
self.changes = function (args, callback) {
console.log("changes");
if (args.since == 0) {
request(self.url + '/work_orders/_changes?descending=true&limit=1', function (err, res, headers) {
var body = JSON.parse(res.body);
var since = body.last_seq;
console.log("Since change: "+since);
self.longPoll(since, callback);
});
} else {
self.longPoll(args.since, callback);
}
}
self.longPoll = function (since, callback) {
console.log("about to request with: "+since);
request(self.url + '/work_orders/_changes?feed=continuous&include_docs=true&since=' + since,
function (err, res, headers) {
console.log("finished request.")
if (err) { console.log("Error starting long poll: "+err.reason); return; } //if err send it back
callback(err, res.body);
});
}
【问题讨论】:
-
node 绝对可以处理很多到 couchdb 的连接。你能分享如何处理连接的代码吗?
-
已更新代码。我想知道是否需要将我的请求推送到一个数组中并跟踪它们?那么当新的请求以某种方式出现时,只是将它们放在以前提出的请求上?还是取消旧请求并创建新请求?
-
我看不出请求端有什么问题。您不需要跟踪所有长轮询请求。我怀疑冻结来自一些你无法摆脱的沉重循环,所以也许尝试在你的回调中搜索那些
-
我认为使用请求库创建一个长轮询到沙发是在某种程度上造成了问题。首先我正在轮询节点,然后节点对 Couchdb 运行长轮询。但是当我更改我的代码以便 Node 不会长时间轮询沙发,而是每 5 秒短轮询一次,并且当有更改时发送响应时,它就可以工作了。
-
我想我可能会尝试切换到这个库以备将来使用:
标签: node.js express couchdb long-polling