私はJavaライブラリ、実際にはClojureライブラリを書いていますが、この質問では、JVM上で実行されることが重要です。このライブラリはJavaScriptを実行する必要があります。 Nashorn で試しましたが、克服するのが難しい制限がいくつかあります。別の方法として、NodeJSを試してみたいと思います。
NodeJSを独立して実行しているシステムに依存しないように、ライブラリを自己完結型にしたいので、JavaおよびNodeJSアーティファクトを適切な場所に配置するための特定のデプロイメントメカニズムが必要です。 2つの異なるネットワークサーバー。ただし、このアプローチにはいくつかの問題があります。
HTTP経由でNodeJSと通信しますが、NodeJSに特定のポートを開かせたくありません。衝突がないように、ランダムに未使用のものを見つけたいです。また、NodeJSからのログの移動先を制御して、アプリケーションの他の部分と一緒にログを保持したいと思います。最後に、私のアプリはNodeJSがクラッシュしたことを検出して再実行するか、情報とともにエラーを報告できるはずです。
これにアプローチするための最良の方法は何ですか?この方法で子プロセスを管理するのに役立つJavaライブラリはありますか?特にNodeJS側から行う必要があります(私はNodeJSを初めて使用するため、これまで使用したことはありません)。
最終的な私の解決策は、次のように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))
次に、その中でstartを呼び出します。継承IOにより、その出力は現在のプロセスの出力に送られ、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.")))))
Javaでjavascriptを実行する方法についてはかなり良い答えがあります ここ 。そのようなことはあなたの場合に実行可能でしょうか?ここにない場合は、いくつかのリソースがあります。
ノード内で多くのCPUを使用しているようです。その場合は、おそらく クラスターモジュール を使用することをお勧めします(したがって、nodejsは複数のコアを利用できます)。イベントループをブロックすると(CPUベースの処理では、フォークされたプロセスごとに1つの同時リクエストしか実行できなくなります)。
私はpythonスクリプトからfortranを実行しなければならなかったのと同じような立場にあったので、ここに2セントがあります。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.jsプログラムを何に使用しているかはわかりませんが、これが役立つかどうかはわかりません。
Nashornには、いくつかのAPIに関する情報の検索(ドキュメント化には多くの要望が残されています)や起動の遅さなど、私が遭遇したいくつかの問題もあります。
代わりに私がお勧めするのは、サーバー側のレンダリングを子プロセスではなくサービスとして扱うことです。 。
言い換えると、たとえばポート10015
の内部ネットでNode.jsインスタンスを実行し、そのインスタンスへのローカル接続のみを許可することができます(必要な場所にログを送信することもできます)。次に、localhost:10015/posts/
など、レンダリングするページを使用してサービスにリクエストを送信し、そのNode.jsアプリでヘッドレスブラウザー内でページをレンダリングすることができます(PhantomやSlimerなどを使用)。
Nodeサーバーを稼働状態に保つには、Forever
またはsupervisord
を使用できます。また、トラクションをより速く獲得するために、Prerenderチームが何を持っているかを確認できます。作成: https://github.com/prerender/prerender-node