我想设计一个实时更新的 Node.js Express 服务器,可能有一个特定的路由,比如/update,它加载一个新的配置文件。我现在唯一担心的是,更新发生时服务器可能处于任何状态。如果我在正在处理用户请求的 JS 消息时加载新的配置文件,则在用户请求开始时可能有一个配置,在请求完成之前加载新配置文件时可能有第二个配置。我能想到的防止这种情况的唯一方法是关闭服务器至少一分钟(保持服务器运行,但完全阻止任何传入请求),然后更新服务器并将其重新上线,但这并不是真正的情况热重载或实时更新的最佳形式是什么呢?
如何以某种方式欺骗 JS 事件循环,以便仅在所有请求完成后才加载配置文件,并将任何新请求延迟到配置加载之后?
一种算法是:
- 设置一个标志“开始重新配置”
- 上述标志会阻止处理任何新请求(使用 Express 中间件)
- 检查当前所有请求是否已完成(这里想不出比轮询循环更好的方法了)
- 完成上述检查后,加载新配置
- 加载配置后,将标志从 (1) 切换
最佳答案
Disclaimer: I have not tried this in production. In fact, I have not tried this at all. while I believe the idea is sane, there may be hidden pitfalls along the road which are not currently known to me.
许多 Node.js 开发人员往往会忘记/没有完全意识到一件事:
一次只能执行一个 JavaScript 语句。
您可以稍后执行异步 I/O 或执行函数,这并不重要。无论你如何努力,你编写的所有 JS 代码都是在单线程中执行的,没有并行性。只有底层实现(完全不受我们控制)可以并行执行操作。
这对我们很有帮助,因为只要我们的更新过程是同步的,就不能执行其他 JS 代码(即客户端响应)。
配置实时修补
防止请求中配置更改的解决方案相当简单:
每个请求都会获取自己的应用程序配置副本。
如果应用程序的配置位于 JavaScript 对象中,则只需为每个新请求克隆该对象即可。这意味着即使您突然更改配置,它也只会应用于新的传入请求。
There are tons of modules for cloning (even deep cloning) objects, but since I believe mine is best I will use this opportunity for some small self-promotion - semantic-merge.
代码实时修补
这有点棘手,但通常只要付出足够的努力就可以实现。
这里的技巧是首先 remove/unregister current Express routes ,清除Node's require
cache ,再次需要
更新的文件并重新注册路由处理程序。现在,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!
}
关于javascript - 实时更新 Node.js 服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30786875/