NodeJS при выполнении Добавление / удаление / перезагрузка требует БЕЗ перезапуска сервера (No nodemon тоже) - PullRequest
0 голосов
/ 15 октября 2019

У меня есть проект для работы, где я в основном создаю форму CMS, к которой мы будем добавлять приложения по мере продвижения вперед.

Проблема, с которой мы сталкиваемся, заключается в загрузке этих приложений (и другихспециально изменено) во время выполнения на сервере.

Причина, по которой мы требуем эту форму «горячей загрузки», заключается в том, что мы не хотим, чтобы сервер перезагружался при каждом изменении, и многое другоев частности, мы хотели бы добавить новые приложения через панель администратора.

Nodemon - полезный инструмент для разработки, но для нашей производственной среды мы хотим иметь возможность заменить существующее приложение (или модуль / плагин). если хотите) без перезапуска сервера (будь то вручную или через nodemon, сервер должен работать постоянно).

Вы можете сравнить это с CMS, например, с Drupal, Yoomla или Wordpress. делать что-то, но для наших нужд мы решили, что по многим причинам Node - лучший путь.

Код мудрый,Я ищу что-то вроде этого, но это сработает:

let applications = []

//add a new application through the web interface calling the appropiate class method, within the method the following code runs:
applications.push(require('path/to/application');


//when an application gets modified:
applications.splice(index,1);
applications.push('path/to/application');

Но мне нужно также настроить существующие экземпляры указанного приложения.

Пример:

// file location: ./Applications/application/index.js
class application {
   greet() {
      console.log("Hello");
   }
}

module.exports = application;

загрузчик приложения будет загружаться в указанное приложение:

class appLoader {
    constructor() {
        this.List = new Object();
    }

   Add(appname) {
        this.List[appname] = require(`./Applications/${appname}/index`);
   }

    Remove(appname) {
        delete require.cache[require.resolve(`./Applications/${appname}/index`)]
        delete this.List[appname];
    }

    Reload(appname) {
        this.Remove(appname);
        this.Add(appname);
    }
}

Рабочий код:

const AppLoader = require('appLoader');
const applications = new AppLoader();
applications.add('application'); // adds the application created above
var app = new applications.List['application']();

app.greet();
// Change is made to the application file, .greet() now outputs "Hello World" instead of "Hello"
//do something to know it has to reload, either by fs.watch, or manual trigger
applications.Reload('application');
app.greet();

Ожидаемое поведение:

Hello
Hello World

В действительности, Я получаю:

Hello
Hello

Если кто-нибудь может помочь мне найти способ динамической загрузки таких приложений, как это, но также удалить / перезагрузить их во время выполнения, это было бы очень полезно!

Редактировать: если есть способ запустить код моего приложения без использования require, который бы позволил динамическую загрузку / перезагрузку / удаление, это также приветствуемое решение

1 Ответ

1 голос
/ 21 октября 2019

Хорошо, благодаря @ jfriend00, я понял, что мне нужно исправить что-то еще с моим кодом, чтобы его комментарии все еще могли быть полезны для других людей. Что касается моей проблемы выгрузки необходимых модулей или перезагрузки их без перезапуска сервера, я нашел довольно элегантный способ сделать это. Позвольте мне начать с показа всех моих тестовых классов и app.js, и я объясню, что я сделал и как это работает.

Class.js:

"use strict";

class Class {
    constructor() {
// this.file will be put in comments post run-time, and this.Output = "Hey" will be uncommented to change the source file. 
        var date = new Date()
        this.Output = date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds() + "." + date.getMilliseconds();
        this.file = global.require.fs.readFileSync('./file.mov');
        //this.Output = "Hey";
    }
}

module.exports = Class;

app.js:

'use strict';
global.require = {
    fs: require('fs')
};
const arr = [];
const mod = './class.js'
let Class = [null];
Class[0] = require(mod);
let c = [];
c.push(new Class[0]());
console.log(c[0].Output);
console.log(process.memoryUsage());
setTimeout(() => {
    delete require.cache[require.resolve(mod)];
    delete Class[0];
    Class[0] = require(mod);
    console.log(Class)
    delete c[0];
    c[0] = new Class[0]();
    console.log(c[0].Output);
    console.log(process.memoryUsage());
}, 10000);

Теперь позвольте мне объяснить здесь немного, и учтите, что это тестовый код, поэтому наименование просто ужасно.

Вот как я приступил к работе:

Шаг 1

Мне нужен был способ разделения необходимых модулей (таких как fs или websocket, express и т. Д.), Чтобы он не мешалвся delete require_cache() часть кода, мое решение делало это глобально необходимым:

global.required = {
    fs: require('fs')
}

Шаг 2

Найдите способ убедиться, что сборщик мусора удаляет выгруженный код , я добился этого, поместив свои объявления require и class внутри переменной, чтобы я мог использовать функциональность delete в Node / Javascript. (Я использовал let в своем тестовом коде, потому что я тестировал другой метод заранее, не проверял, будет ли const работать снова). Я также создал переменную, которая содержит строку пути для файла (в данном случае '. / Class.js' , но для пояснения ниже я просто напишу его как есть)

let Class = [null] //this declares an array that has an index '0'
Class[0] = require('./Class');

let c = [new Class[0]()] // this declares an array that has the class instantiated inside of index '0'

Что касается сборки мусора, я просто могу сделать следующее:

delete Class[0];
delete c[0];

После этого я могу повторить объявление требуемого класса, а затем самого класса и сохранить свойкод работает без перезапуска.

Помните, что для его реализации в реальном проекте требуется немало усилий, но вы можете разделить его, добавив метод unload () в класс длявыгрузить базовые пользовательские классы. Но мое первоначальное тестирование показывает, что это работает как шарм!

Редактировать: я чувствую, что должен отметить, что без комментариев jfriend00 я бы никогда не нашел это решение

Вывод

При запуске проекта выводится текущее время и process.memoryUsage()

13:49:13.540
{ rss: 50343936,
  heapTotal: 7061504,
  heapUsed: 4270696,
  external: 29814377 }

в течение 10 секунд ожидания, я изменяю файл Class.js, чтобы он не читалсяfile.mov и сказать «Привет» вместо времени, после тайм-аута 10 с это вывод:

Hey
{ rss: 48439296,
  heapTotal: 7585792,
  heapUsed: 4435408,
  external: 8680 }
...