javascript - principiantes - ¿Cómo debo ejecutar NodeJS desde una aplicación Java?
node js vs java español (4)
Nashorn también tiene algunos problemas que me he encontrado, como encontrar información sobre algunas de sus API (la documentación deja mucho que desear) y el lento arranque.
Lo que recomendaría en su lugar: trate su representación del lado del servidor como un servicio y no un proceso secundario .
En otras palabras, podría ejecutar una instancia de Node.js en su red interna en el puerto de decir 10015
y solo permitir conexiones locales (también podría enviar registros a donde lo desee). Luego puede realizar una solicitud al servicio con las páginas que desea mostrar, como localhost:10015/posts/
y hacer que la aplicación Node.js muestre la página dentro de un navegador sin cabeza (usando algo como Phantom o Slimer).
Para mantener su servidor Node activo, puede usar Forever
o supervisord
, y para ayudarlo a ganar tracción más rápido, puede ver lo que ha hecho el equipo de Prerender: https://github.com/prerender/prerender-node
Estoy escribiendo una biblioteca Java, en realidad, una biblioteca Clojure, pero para esta pregunta, lo importante es que se ejecute en la JVM. Esta biblioteca necesita ejecutar algo de JavaScript. Intenté con Nashorn pero encuentro algunas limitaciones que pueden ser muy difíciles de superar. Como alternativa, quiero probar NodeJS.
Quiero que mi biblioteca sea independiente, que no dependa del sistema que ejecuta NodeJS de forma independiente y que requiera un mecanismo de implementación particular para ubicar los artefactos Java y NodeJS en los lugares correctos para ser recogidos por los dos servidores de red diferentes. Este enfoque, sin embargo, trae algunos problemas.
Hablaré con NodeJS a través de HTTP, pero no quiero que NodeJS abra un puerto específico. Quiero encontrar uno aleatorio sin usar para que no haya colisiones. También quiero controlar dónde van los registros de NodeJS, para mantenerlos con el resto de mi aplicación. Por último, mi aplicación debería poder detectar cuándo NodeJS se bloqueó y volver a ejecutarlo o informar un error con información.
¿Cuál es la mejor manera de abordar esto? ¿Hay alguna biblioteca de Java para ayudar a administrar el proceso hijo de esta manera? Cualquier cosa en particular que debería hacer desde el lado NodeJS (soy muy nuevo en NodeJS, nunca lo he usado antes).
He estado en una posición similar donde tuve que ejecutar Fortran desde un script de Python, así que aquí está mi granito de arena. Ejecute su script node.js con un comando de terminal en Java como este:
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);
}
Con la configuración puede pasar parámetros a su programa de nodo y obtener respuestas. Aunque no estoy seguro para qué está usando su programa node.js, entonces no estoy seguro si esto es útil.
Mi solución al final fue usar ProcessBuilder así:
(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))
y luego llamar a comenzar en él. inheritIO hace que la salida de la misma llegue al resultado del proceso actual que fusiona de manera efectiva stdout y stderr.
Además de eso, NodeJS abre un puerto aleatorio al especificar 0 como el número de puerto y lo escribe en un archivo:
(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)))))))))
que luego se abre por el lado de Java (esperando que aparezca):
(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.")))))
Aquí hay una muy buena respuesta sobre cómo ejecutar javascript en java. ¿Sería algo así para su caso? Si no, aquí hay algunos recursos:
- Puerto aleatorio en nodejs Puede acceder a otro servicio más para encontrar un puerto abierto durante la compilación, o hacer que su aplicación de nodo ejecute una solicitud http a su servidor Java en función del puerto que capta.
- Winston es la mejor biblioteca de registro que he encontrado, no debería tener problemas para iniciar sesión en la misma ruta.
- Forever y PM2 son los gestores de procesos de nodos comunes que mantienen el nodo en funcionamiento. Actualmente prefiero para siempre (no estoy seguro de por qué)
Parece que usará mucha CPU dentro del nodo. Si ese es el caso, probablemente desee utilizar el módulo de clúster (para que nodejs pueda utilizar múltiples núcleos). Si bloquea el bucle de evento (que será el procesamiento basado en la CPU, entonces solo podrá realizar 1 solicitud concurrente por proceso bifurcado).