停止/中止/终止所需已加载模块

问题描述

是否有可能停止/中止/终止所需/加载的模块?

在这里 (https://stackoverflow.com/a/6677355/5781499) 找到了一些东西:

var name = require.resolve('moduleName');
delete require.cache[name];

但这不会停止/中止正在运行的计时器或类似的东西。 它只是继续做脚本所做的事情。

我需要这个的原因,我想实现一个插件系统,您可以在其中启动和停止插件

“开始”很容易,只需加载 require(...) 代码。 但是,停止插件正在执行的所有操作的最佳方法是什么?

我想过一个虚拟机,但在节点中没有办法中止虚拟机执行。 我想到的下一件事是“工作线程”。他们提供了一个 .terminate 方法来满足我的需求。 (但现在我要处理进程间通信,保持一切同步非常复杂)

如果有人能给我一个提示/技巧就好了。

解决方法

Nodejs 不提供任何功能来做你想做的事情,所以你必须手动做很多事情。正如您所发现的,删除模块缓存中的模块只会影响您再次尝试加载代码时发生的情况,而根本不会影响已加载的代码。

如果您要让插件保持在同一进程中,那么您可以在插件中实现一个所需的方法,称为“关闭”,插件手动关闭自身(停止计时器,取消注册事件处理程序等...)。正确实施,这应该将其与 nodejs 程序中的任何内容完全断开。如果随后从 require 缓存中删除模块,则可以在其位置加载新模块。这样做的一个缺点是 nodejs 永远不会卸载原始代码——它只是留在内存中。如果您没有访问原始模块句柄,则该代码将永远不会再被使用,但它不会被 nodejs 释放或回收。

一个更健壮的系统是将每个插件放在它们自己的子进程或工作线程中,并通过父进程和子进程之间的内置进程间通信(本质上只是消息传递)与它们通信。只要您不必在父子/工人之间发送大量数据或拥有超高带宽数据,那么消息传递使用起来非常简单并且效果很好。

如果使用单独的子进程,您可以随时终止子进程,操作系统将回收该进程使用的所有资源(对于 workerThread 而言并非如此)。这有其自身的缺点,因为它可能会使用更多内存,因为一个全新的 nodejs 进程或 nodejs 中的 workerThread 比仅仅将单个模块加载到现有的 nodejs 进程中要重得多。

在子进程中运行它的优势在于,您的主进程可以更好地保护插件中的错误代码(无论是意外的还是恶意的),因为它们是不同的进程,插件不能直接干扰父进程。但是,不要在这里自欺欺人,除非您在沙盒 VM 中运行它,否则该插件仍然会对系统造成严重破坏,因为它可以访问系统上的许多资源(磁盘、网络、其他外围设备等)。 ..).