Подтвердить что ты не робот

Как запустить NodeJS из приложения Java?

Я пишу библиотеку Java, фактически, библиотеку Clojure, но для этого вопроса важно, что она работает на JVM. Эта библиотека должна выполнить некоторый JavaScript. Я пробовал с Nashorn, но я сталкиваюсь с некоторыми ограничениями, которые могут быть слишком сложными для преодоления. В качестве альтернативы, я хочу попробовать NodeJS.

Я хочу, чтобы моя библиотека была автономной, чтобы не зависать от системы, запускающей NodeJS, и тем самым требовать, чтобы определенный механизм развертывания помещал артефакты Java и NodeJS в нужные места, которые должны были быть захвачены двумя разными сетевыми серверами. Однако этот подход вызывает некоторые проблемы.

Я буду разговаривать с NodeJS через HTTP, но я не хочу, чтобы NodeJS открывал определенный порт. Я хочу найти случайный неиспользованный, чтобы не возникало столкновений. Я также хочу контролировать, где идут журналы из NodeJS, чтобы сохранить их с остальной частью моего приложения. Наконец, мое приложение должно иметь возможность обнаруживать, когда NodeJS разбился и повторно запустить его или сообщить об ошибке с информацией.

Какой лучший способ приблизиться к этому? Существуют ли какие-либо библиотеки Java, чтобы помочь управлять дочерним процессом таким образом? Что-нибудь, что я должен делать со стороны NodeJS (я очень новичок в NodeJS, я никогда не использовал его раньше).

4b9b3361

Ответ 1

Моим решением в конце было использовать ProcessBuilder следующим образом:

(defn create-process-builder [js-engine]
  (doto (ProcessBuilder. ["node" (:path js-engine)
                          "--port-file" (:port-file js-engine)
                          "--default-ajax-host" (:default-ajax-host js-engine)
                          "--default-ajax-port" (str (:default-ajax-port js-engine))])
    .inheritIO))

а затем запустите его. inheritIO приводит к тому, что он выводит на выход текущего процесса, который эффективно объединяет stdout и stderr.

В дополнение к этому NodeJS открывает случайный порт, указав 0 в качестве номера порта и записывая его в файл:

(let [app (-> (express)
              (.use (cookie-parser))
              (.get "/" (fn [_req res] (.send res "Universal JavaScript engine for server side pre-rendering single page applications.")))
              (.get "/render" render))
      server (.createServer http app)]
  (.listen server 0 (fn [] (.writeFile fs (:port-file options) (.-port (.address server)))))))))

который затем открывается стороной Java (ожидая ее появления):

(defn get-port-number [js-engine]
  (or (with-timeout
        (:start-timeout js-engine)
        (loop [port-number (read-port-file js-engine)]
          (if (string/blank? port-number)
            (if (is-running? js-engine)
              (do (Thread/sleep 100)
                  (recur (read-port-file js-engine)))
              (throw (Exception. (str "While waiting for port number, process died: " (:path js-engine)))))
            port-number)))
      (throw (Exception. (str "Waited for " (:start-timeout js-engine) " for " (:path js-engine) " to start and report its port number but it timed out.")))))

Ответ 2

Здесь есть довольно хороший ответ о том, как запустить javascript в java. Будет ли что-то подобное для вашего дела? Если нет, то некоторые ресурсы:

  • Случайный порт в nodejs. Вы можете нажать еще одну услугу, чтобы найти открытый порт во время сборки, или использовать огонь приложения node HTTP-запрос на ваш Java-сервер на основе порта, который он захватывает.
  • Winston - лучшая библиотека регистрации, которую я обнаружил, у вас не должно быть проблем, связанных с тем же путем.
  • Forever и PM2 являются обычными менеджерами процессов node, которые поддерживают node. Я в настоящее время предпочитаю навсегда (не уверен, почему)

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

Ответ 3

У Nashorn есть некоторые проблемы, с которыми я столкнулся, например, поиск информации о некоторых из их API (документация оставляет желать лучшего) и медленную загрузку.

Что бы я рекомендовал вместо этого: обработайте рендеринг на стороне сервера как службу, а не дочерний процесс.

Другими словами, вы можете запустить экземпляр Node.js в своей внутренней сети на порту 10015 и разрешить только локальные подключения (вы также можете отправлять журналы везде, где захотите). Затем вы можете сделать запрос к службе со страницами, которые вы хотите визуализировать, например localhost:10015/posts/, и сделать это приложение Node.js отображать страницу внутри браузера без браузера (используя что-то вроде Phantom или Slimer).

Чтобы сохранить сервер Node, вы можете использовать Forever или supervisord, и чтобы ускорить ускорение, вы можете посмотреть, что сделала команда Prerender: https://github.com/prerender/prerender-node

Ответ 4

Я был в аналогичной позиции, где мне пришлось запускать fortran из python script, так что вот мои два цента. Запустите node.js script с помощью команды терминала в Java, например:

Runtime rt = Runtime.getRuntime();
String[] commands = {"node example.js", "args"};
Process proc = rt.exec(commands);

BufferedReader stdInput = new BufferedReader(new 
     InputStreamReader(proc.getInputStream()));

BufferedReader stdError = new BufferedReader(new 
     InputStreamReader(proc.getErrorStream()));

// read the output from the command
System.out.println("Here is the standard output of the command:\n");
String s = null;
while ((s = stdInput.readLine()) != null) {
    System.out.println(s);
}

// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
    System.out.println(s);
}

С настройкой вы можете передать параметры вашей программе node и получить ответы. Хотя я не уверен, что вы используете вашу программу node.js, так что не уверен, что это полезно.