I'm writing a Java library, actually, a Clojure library, but for this question, what matters is that it runs on the JVM. This library needs to execute some JavaScript. I tried with Nashorn but I encounter some limitations that might be too hard to overcome. As an alternative, I want to try NodeJS.
I want my library to be self contained, to not depend on the system running NodeJS independently and thus requiring a particular deployment mechanism to place the Java and NodeJS artifacts in the right places to be picked up by the two different network servers. This approach, though, brings some issues.
I will be talking to NodeJS over HTTP but I don't want NodeJS to open a specific port. I want to find a random unused one so there's no collisions. I also want to control where the logs from NodeJS go, as to keep them with the rest of my application. Lastly, my app should be able to detect when NodeJS crashed and re-run it or report an error with information.
What's the best way to approach this? Are there any Java libraries to help manage child process in this fashion? Anything in particular I should do from the NodeJS side (I'm very new to NodeJS, I never used it before).
I have been in a similar position where I had to run fortran from a python script, so here is my two cents. Run your node.js script with a terminal command in Java like this:
With setup you can pass in parameters to your node program and get responses. Although I am not sure what you are using your node.js program for, so not sure if this is helpful.
My solution in the end was to use ProcessBuilder like this:
and then call start in it. inheritIO causes the output of it to go to the output of the current process which effectively merges stdout and stderr.
On top of that NodeJS opens a random port by specifying 0 as the port number and writes it to a file:
which then is opened by the Java side (waiting for it to appear):
Nashorn does have some issues that I've run into as well, such as finding information about some of their APIs (documentation leaves a lot to be desired), and the slow boot up.
What I would recommend instead: treat your server-side rendering as a service and not a child process.
In other words, you could run a Node.js instance on your internal net on say port
10015
and only allow local connections to it (you could also send logs wherever you want). Then you can make a request to the service with the pages that you want to render, such aslocalhost:10015/posts/
and have that Node.js app render the page inside of a headless browser (using something like Phantom or Slimer).To keep your Node server up, you can use
Forever
orsupervisord
, and to help you gain traction faster, you could look at what the Prerender team has made: https://github.com/prerender/prerender-nodeThere is a pretty good answer here on how to run javascript in java. Would something like that be doable for your case? If not here are some resources:
It sounds like you will be using a lot of cpu within node. If that is the case you will probably want to use the cluster module (so nodejs can utilize multiple cores). If you block the event loop (which cpu based processing will, then you will only be able to perform 1 concurrent request per forked process).