实时更新Node.js服务器

时间:2015-06-11 16:53:51

标签: javascript node.js express

我想设计一个实时更新的Node.js Express服务器,可能有一个特定的路由,例如/ update,它会加载一个新的配置文件。我现在唯一担心的是,当更新发生时,服务器可能处于任何状态。如果在为用户请求处理JS消息时加载新配置文件,则在用户请求开始时可能有一个配置,在请求完成之前,可能会在加载新配置文件时进行第二次配置。我能想到的唯一方法就是将服务器关闭至少一分钟(保持服务器正常运行,但完全阻止任何传入的请求),然后更新服务器并将其重新联机,但那不是真的最好的热重装或实时更新形式是吗?

我怎样才能以某种方式欺骗JS事件循环,以便配置文件只在所有请求完成后才加载并延迟任何新请求,直到加载配置为止?

一种算法是:

  1. 设置标志“开始重新配置”
  2. 以上标志可防止处理任何新请求(使用Express中间件)
  3. 检查所有当前请求是否已完成(无法想到比此处的轮询循环更好的任何内容)
  4. 完成上述检查后,加载新配置
  5. 加载配置后,从(1)
  6. 切换标志

3 个答案:

答案 0 :(得分:3)

  

免责声明:我没有在生产中试过这个。事实上,我根本没有尝试过这个。虽然我认为这个想法是理智的,但沿路可能存在隐藏的陷阱,这些陷阱目前还不为我所知。

许多Node.js开发人员往往会忘记/没有完全意识到这一点:

一次只能执行一个JavaScript语句。

您可以稍后执行异步I / O或执行某项功能并不重要。无论你怎么努力,你编写的所有JS代码都在一个线程中执行,没有并行性。只有底层实现(完全不受我们控制)才能并行执行。

这对我们有所帮助,因为只要我们的更新过程是同步的,就不能执行其他JS代码(即客户端响应)。

配置实时修补

在请求中阻止配置更改的解决方案非常简单:

每个请求都有自己的应用程序配置副本。

如果应用程序的配置位于JavaScript对象中,则只需为每个新请求克隆该对象。这意味着即使您突然更改配置,它也只会应用于新的传入请求。

  

有很多用于克隆(甚至深度克隆)对象的模块,但由于我相信我的最好,我将利用这个机会进行一些小的自我推销 - semantic-merge

代码实时修补

这有点棘手,但通常应该付出足够的努力。

这里的技巧是首先remove/unregister current Express routes,再次清除Node's require cacherequire更新的文件并重新注册路由处理程序。现在,Express将使用旧代码完成所有待处理请求(这是因为只要代码包含活动对象引用,Node就无法从内存中删除这些旧函数 - 它会执行 - reqres)和使用新需要的模块/路由来处理新的传入请求。一旦没有更多以旧代码开头的请求,旧代码就应该从内存中释放出来。

在请求处理期间,您不得在任何地方使用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,这将对您有所帮助:

Socket.io with NodeJS

服务器将等待某个用户或任何人的信号并向所有用户发出信号,以便他们获取新数据

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'端点。

这个方案可能对你有用......