2

J2EEWebアプリからトリガーしたいシェルスクリプトがあります。

スクリプトは、処理、FTPなど、多くのことを実行します。これはレガシーなことです。

実行には長い時間がかかります。

これに対する最善のアプローチは何だろうかと思います。ユーザーがリンクをクリックしてスクリプトをトリガーし、スクリプトが開始されたことを示すメッセージをユーザーに表示できるようにしたいと思います。スクリプトの実行に長い時間がかかるという事実に関係なく、HTTP要求/応答サイクルを瞬時に実行したいと思います。

私は3つのオプションを考えることができます:

  • ユーザーのクリックの処理中に新しいスレッドを生成します。ただし、これはJ2EE仕様に準拠しているとは思いません。
  • スクリプトをトリガーする前に、HTTP応答ストリームに出力を送信してコミットします。これにより、HTTP要求/応答サイクルが終了したように見えますが、実際には、要求を処理しているスレッドは、シェルスクリプトが終了するのを待ってそこにとどまっています。だから私は基本的に私自身の目的のためにコンテナのHTTP処理スレッドをハイジャックしました。
  • メインスクリプトをバックグラウンドで開始するラッパースクリプトを作成します。これにより、リクエスト/レスポンスサイクルがコンテナ内で正常に終了します。

上記はすべて、サーブレットとRuntime.getRuntime()。exec()を使用します。

これは、Java1.4.2でOracleのOC4Jアプリサーバーを使用するSolarisで実行されます。

誰が最もハッキーな解決策であるか、そしてその理由について何か意見がありますか?

それとも誰かがより良いアプローチを持っていますか?Quartzを利用できますが、シェルスクリプトをJavaプロセスとして再実装する必要はありません。

ありがとう。

4

8 に答える 8

3

あなたはクォーツについて言及したので、オプション#4(もちろんIMOが最高です)に行きましょう:

PS:最大の問題はドキュメントを見つけることかもしれません、そしてこれは私が見つけることができた最高の情報源です:NativeJobの使い方?

于 2009-09-29T16:56:43.527 に答える
2

特に、スクリプトがいつ終了するかを実際に知る必要がない場合(または、プロセスが終了するのを待つ以外の方法で調べる必要がある場合)は、オプション3を使用します。

オプション1は、スクリプトが終了するのを待っているだけのスレッドを無駄にします。オプション2は悪い考えのようです。サーブレットコンテナスレッドを乗っ取ることはありません。

于 2009-09-29T16:43:31.713 に答える
2

アプリケーションが開始しているスクリプトからの出力を評価する必要がありますか、それともこれは単純なファイアアンドフォーゲットジョブですか?必要がない場合は、Runtime.getRuntime()。exec()がすぐに戻り、プロセスがバックグラウンドで実行され続けるという事実を「悪用」することができます。スクリプト/プロセスが終了するのを実際に待ちたい場合は、exec()によって返されたProcessオブジェクトに対してwaitFor()を呼び出す必要があります。

開始するプロセスがstdoutまたはstderrに何かを書き込む場合は、必ずこれらをログファイルまたは/ dev / nullにリダイレクトしてください。そうしないと、stdoutおよびstderrが入力ストリームとして使用可能であり、バッファリング機能が制限されているため、しばらくするとプロセスがブロックされます。プロセスオブジェクト。

于 2009-09-29T18:08:05.083 に答える
1

これに対する私のアプローチは、おそらく次のようなものになるでしょう。

  • 実際の実行を実行するには、サーブレット内にExecutorServiceを設定します。
  • 適切な戻り型を使用してCallableの実装を作成します。これは、実際のスクリプト実行をラップして( Runtime.exec()を使用)、Java入力変数をシェルスクリプト引数に変換し、スクリプト出力を適切なJavaオブジェクトに変換します。
  • リクエストが届いたら、適切なCallableオブジェクトを作成し、それをエグゼキュータサービスに送信して、結果をFuture永続的な場所に配置します(たとえば、ユーザーのセッション、または要件に応じて、後で検索するためにキーをユーザーに返すUIDキー付きマップ)。次に、スクリプトが正常に開始されたことを示すHTTP応答をユーザーにすぐに送信します(必要に応じてルックアップキーを含む)。
  • Futureユーザーがタスクの進行状況をポーリングするためのメカニズムを追加し、検索したばかりの状態に応じて、「まだ実行中」の応答、「失敗」の応答、または「成功+結果」の応答のいずれかを返します。

少し手間がかかりますが、Webアプリの構造によっては、これらの一般的なコンポーネントをどこかに適合させることができます。

于 2009-09-29T16:42:27.110 に答える
1

HTTP応答/ユーザーがスクリプトの出力を確認する必要がない場合、またはスクリプトがいつ完了するかを知っている必要がない場合は、前述のように、スレッドを実行できるように、ある種のラッパースクリプトでスレッドを起動するのが最善のオプションです。サーブレットコンテナ環境全体の外部。これは、コンテナ内のスレッドを管理する必要がないこと、または言及したようにスレッドをハイジャックすることなどから自分自身を免れることができることを意味します。

スクリプトが完了したときやスクリプトの出力を監視したときにユーザーに通知する必要がある場合にのみ、オプション1または2を検討します。

于 2009-09-29T16:43:48.047 に答える
0

問題は、J2EEの「リクエストごとの単一応答」モデルに逆らい、バックエンドタスクの実行時にエンドユーザーのページを動的に更新しようとしているという事実に起因しています。

Ajaxベースのソリューションの導入をやめたくない場合は、バックエンドタスクが完了するまで、ユーザーのブラウザーでレンダリングされたページにサーバーに情報を定期的に「ポーリング」させる必要があります。

これは、次の方法で実現できます。

  1. J2EEコンテナがリクエストを受信すると、セッションオブジェクト(スクリプトの出力を書き込むために使用されます)への参照を取得するスレッドを生成します。

  2. 応答サーブレットを初期化して、定期的(10秒程度ごと)にサーバーからページをリロードするJavascript関数を含むhtmlページを記述します。

  3. リクエストごとに、セッションオブジェクトをポーリングして、手順1で生成されたスレッドによって保存された出力を表示します。

  4. [必要に応じて、スレッドが完了したらセッションから保存されたコンテンツを削除するためのクリーンアップロジックを追加できます。また、スクリプト実行のマーク状態遷移用にセッションに追加のフラグを設定することもできます]

これは、目的を達成するための1つの方法です。すべてのアプローチの中で最も洗練されているわけではありませんが、基本的には、要求/応答モデルを使用して、サーバーからページコンテンツを非同期に更新する必要があるためです。

これを実現する方法は他にもありますが、実際には、制約の柔軟性に依存します。Direct Web Remotingについて聞いたことがありますが(まだ遊んでいませんが)、Reverse-Ajaxを使用したアプリケーションの開発を検討する価値があるかもしれません。

于 2009-09-29T19:18:39.447 に答える
0

2番目のオプションでは、サーブレットを使用できます。HTTPリクエストに応答した後、java.lang.Runtime.exec()を使用してスクリプトを実行できます。こちらもご覧になることをお勧めします:http ://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html

...それを使用する際の問題と落とし穴のいくつかについて。

于 2009-09-29T16:32:16.073 に答える
0

非同期バックエンドプロセスの最も堅牢なソリューションは、メッセージキューIMOを使用することです。最近、Springに埋め込まれたActiveMQブローカーを使用してこれを実装し、生成および消費するBeanをリギングしました。ジョブを開始する必要がある場合、私のコードはプロデューサーを呼び出し、プロデューサーはメッセージをキューに入れます。コンシューマーはキューにサブスクライブされ、別のスレッドのメッセージによって実行に移されます。このアプローチは、UIを(プロデューサーを介して)キューイングメカニズムから、および(コンシューマーによって処理される)非同期プロセスからきちんと分離します。

これは、開発者マシンのTomcatサーバーで実行され、テスト/本番マシンのWeblogicにデプロイされたJava 5、Spring構成の環境であることに注意してください。

于 2009-09-29T18:37:06.770 に答える