Based on the principle of deployment and implementation of nodejs hot line of code

导语 一个让你不用重启nodejs线上服务,就能使新更新代码生效的热部署方案

background

As we all know, nodejs start of back-end services, if there are changes in the code, to restart the process, the code to take effect.
nodejs process at the time of the restart, the user to access the service, there will be short of 502 bad gateway
if your server plus the watch mechanism
when code changes frequently occur on the server, or high-frequency variations occur within a short time, then would have been 502 bad gateway
Recently, in doing online services compile the demand, there have been changes in high-frequency short online service code, the code update function module high frequency, in the case can not restart the service, so updates Code scene in force.
This involves the deployment of a hot concept, without restarting the service, so that the deployment of the new code to take effect.
Next, I come to you to explain the principles and implementations of hot deployment

The reason code can not with immediate effect
when we are through require ( 'xx / xx.js') to load a function module, the result node will require ( 'xx / xx.js') get cached in require.cache ( 'xx / xx.js') in
when we called multiple times require ( 'xx / xx.js') , node will no longer reload, but read directly from require.cache ( 'xx / xx.js') cache
so when the junior partner to modify files in xx / xx.js this path on the server, node will cache to read, not to load the junior partner of the latest code

Source address and use
in order to achieve this hot deployment mechanism, in the online information around, stepped on a lot of the pit was not ready
following code is extracted, hot deployment can run basic principles of the code integrity, we can be based on this code to self-expand: smart -node-reload
note that the latest version of the 12 versions of the node will run error, the official require.cache has been adjusted, the problem has been reported to the official, it is recommended to use nodejs version: v10.5.0
after git clone down, without having to install, run directly

 npm start

This time it turned hot deployment monitor changes

How to see the effect it

Look junior partner /hots/hot.js file

const hot = 1
module.exports = hot

The first line of code to const hot = 111

   const hot = 111
    module.exports = hot

This time you can see inside the terminal to monitor changes in the code, and then dynamically load your code and get the latest execution result, the output is:

热部署文件: hot.js ,执行结果: { 'hot.js': 111 }

Hot deploy service to listen to the code changes, and reload the code, the junior partner in real time you can get the latest results of the implementation of the code, the whole process is running online environment, node does not restart the process

Source resolve

loadHandlers main function

const handlerMap = {};// 缓存
const hotsPath = path.join(__dirname, "hots");

// 加载文件代码 并 监听指定文件夹目录文件内容变动
const loadHandlers = async () => {
  // 遍历出指定文件夹下的所有文件
  const files = await new Promise((resolve, reject) => {
    fs.readdir(hotsPath, (err, files) => {
      if (err) {
        reject(err);
      } else {
        resolve(files);
      }
    });
  });
  // 初始化加载所有文件 把每个文件结果缓存到handlerMap变量当中
  for (let f in files) {
    handlerMap[files[f]] = await loadHandler(path.join(hotsPath, files[f]));
  }

  // 监听指定文件夹的文件内容变动
  await watchHandlers();
};

loadHandlers is the main function of the entire hot deployment services, we specify the hots file in the server root directory folder is used to monitor changes in a file folder and hot deployment of
all folders in the file with fs.readdir scan hots, by loadHandler method to load and run each scanned file will result in the cache to handlerMap
then open the file changes monitor with watchHandlers method
changes watchHandlers monitor file

// 监视指定文件夹下的文件变动
const watchHandlers = async () => {
  // 这里建议用chokidar的npm包代替文件夹监听
  fs.watch(hotsPath, { recursive: true }, async (eventType, filename) => {
    // 获取到每个文件的绝对路径
    // 包一层require.resolve的原因,拼接好路径以后,它会主动去帮你判断这个路径下的文件是否存在
    const targetFile = require.resolve(path.join(hotsPath, filename));
    // 当你适应require加载一个模块后,模块的数据就会缓存到require.cache中,下次再加载相同模块,就会直接走require.cache
    // 所以我们热加载部署,首要做的就是清除require.cache中对应文件的缓存
    const cacheModule = require.cache[targetFile];
    // 去除掉在require.cache缓存中parent对当前模块的引用,否则会引起内存泄露,具体解释可以看下面的文章
	//《记录一次由一行代码引发的“血案”》https://cnodejs.org/topic/5aaba2dc19b2e3db18959e63
	//《一行 delete require.cache 引发的内存泄漏血案》https://zhuanlan.zhihu.com/p/34702356
    if (cacheModule.parent) {
        cacheModule.parent.children.splice(cacheModule.parent.children.indexOf(cacheModule), 1);
    }
    // 清除指定路径对应模块的require.cache缓存
    require.cache[targetFile] = null;

    // 重新加载发生变动后的模块文件,实现热加载部署效果,并将重新加载后的结果,更新到handlerMap变量当中
    const code = await loadHandler(targetFile)
    handlerMap[filename] = code;
    console.log("热部署文件:", filename, ",执行结果:", handlerMap);
  });
};

watchHandlers function is used to monitor files in the specified folder change, clear the cache update the cache with.
With fs.watch native function to listen hots folder file changes when files are changed, even if the absolute file path targetFile
and require.cache [targetFile] that require caching targetFile original file, clear the cache with require.cache [targetFile ] = null;
pit father's place again, just cache set to null, a memory leak occurs, we need to clear the cache parent references require.cache [targetFile] .parent, is the following piece of code

 if (cacheModule.parent) {
        cacheModule.parent.children.splice(cacheModule.parent.children.indexOf(cacheModule), 1);
    }

loadHandler load file

// 加载指定文件的代码
const loadHandler = filename => {
  return new Promise((resolve, reject) => {
    fs.readFile(filename, (err, data) => {
      if (err) {
        resolve(null);
      } else {
        try {
          // 使用vm模块的Script方法来预编译发生变化后的文件代码,检查语法错误,提前发现是否存在语法错误等报错
          new vm.Script(data);
        } catch (e) {
          // 语法错误,编译失败
          reject(e);
          return;
        }
        // 编译通过后,重新require加载最新的代码
        resolve(require(filename));
      }
    });
  });
};

the role of loadHandler function is to load the specified file and check the new file code syntax and so on.
Fs.readFile by reading the contents of the file
with the node native vm module vm.Script way to file a pre-compiled code changes, check the syntax errors in advance found syntax errors and other error
after inspection by, the resolve (require (filename) ) method to re-load the file require and automatically added to the cache require.cache

end:

These are all the contents of the hot deployment, code address is: smart-node-reload
this code is the code I passed minimalist, facilitate reading and comprehension, little interested partners can go deep step to expand by this Code

Above are some of my own thoughts, to share out the welcome to correct me, the way to find a wave of concern
Here Insert Picture Description

Published 19 original articles · won praise 7 · views 6457

Guess you like

Origin blog.csdn.net/ZYQZXF/article/details/104435080