我想设计一个实时更新的Node.js Express服务器,可能有一个特定的路由,例如/ update,它会加载一个新的配置文件。我现在唯一担心的是,当更新发生时,服务器可能处于任何状态。如果在为用户请求处理JS消息时加载新配置文件,则在用户请求开始时可能有一个配置,在请求完成之前,可能会在加载新配置文件时进行第二次配置。我能想到的唯一方法就是将服务器关闭至少一分钟(保持服务器正常运行,但完全阻止任何传入的请求),然后更新服务器并将其重新联机,但那不是真的最好的热重装或实时更新形式是吗?
我怎样才能以某种方式欺骗JS事件循环,以便配置文件只在所有请求完成后才加载并延迟任何新请求,直到加载配置为止?
一种算法是:
答案 0 :(得分:3)
免责声明:我没有在生产中试过这个。事实上,我根本没有尝试过这个。虽然我认为这个想法是理智的,但沿路可能存在隐藏的陷阱,这些陷阱目前还不为我所知。
许多Node.js开发人员往往会忘记/没有完全意识到这一点:
一次只能执行一个JavaScript语句。
您可以稍后执行异步I / O或执行某项功能并不重要。无论你怎么努力,你编写的所有JS代码都在一个线程中执行,没有并行性。只有底层实现(完全不受我们控制)才能并行执行。
这对我们有所帮助,因为只要我们的更新过程是同步的,就不能执行其他JS代码(即客户端响应)。
在请求中阻止配置更改的解决方案非常简单:
每个请求都有自己的应用程序配置副本。
如果应用程序的配置位于JavaScript对象中,则只需为每个新请求克隆该对象。这意味着即使您突然更改配置,它也只会应用于新的传入请求。
有很多用于克隆(甚至深度克隆)对象的模块,但由于我相信我的最好,我将利用这个机会进行一些小的自我推销 - semantic-merge。
这有点棘手,但通常应该付出足够的努力。
这里的技巧是首先remove/unregister current Express routes,再次清除Node's require
cache,require
更新的文件并重新注册路由处理程序。现在,Express将使用旧代码完成所有待处理请求(这是因为只要代码包含活动对象引用,Node就无法从内存中删除这些旧函数 - 它会执行 - req
和res
)和使用新需要的模块/路由来处理新的传入请求。一旦没有更多以旧代码开头的请求,旧代码就应该从内存中释放出来。
在请求处理期间,您不得在任何地方使用require
,否则您可能会遇到与更改请求中的配置相同的问题。您当然可以在模块级范围内使用require
,因为这将在需要模块本身时执行,因此是同步的。
示例:
// app/routes/users.js (or something)
// This is okay, because it is executed only once - when users.js
// itself is required
var path = require('path')
// This function is something you would put into app.use()
module.exports = function usersRoute (req, res, next) {
// Do not use require() here! It will be executed per-request!
}
答案 1 :(得分:1)
我认为不是将请求循环到服务器,而是可以使用Websocket。
这样,当您提到的配置文件发生更改时,服务器可以向用户“发出”消息,以便他们刷新数据。
如果您使用的是nodeJS和Express,这将对您有所帮助:
服务器将等待某个用户或任何人的信号并向所有用户发出信号,以便他们获取新数据
Node.js的:
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket')(server);
var port = process.env.PORT || 3000;
server.listen(port, function () {
console.log('Server listening at port %d', port);
});
app.use(express.static("/PATH_TO_PROJECT"));
io.on('connection', function (socket) {
socket.on('someone update data', function (data) {
socket.to(socket.room).broadcast.emit('data updated', {params:"x"});
}
});
同时,如果有任何变化,客户将会收听:
View.js:
var socket = io();
socket.on('new message', function (data) {
liveUpdate(data);
});
我希望我能正确理解你的要求
答案 2 :(得分:1)
这是一个很好的问题需要解决。
可能的解决方案可能是: 您从父控制器派生每个路径上的控制器。父控制器可以在请求到达时标记属性ON(标志/文件),并在发送响应时将其关闭。
现在为面向前端的每个快速端点子类化此父控制器。如果您现在请求'/ update',更新控制器将通过FLAG知道服务器是否正忙,如果更新成功,则发回回复。
对于更新失败,前端可能会使用一些退避方案回发到'/ update'端点。
这个方案可能对你有用......