この質問の動機 非常に高価なハードウェアで動作する巨大な製品を実行しています。テスト目的でシャットダウンすることはできません。また、実稼働環境に悪い jar を配置することもできません。本番環境を台無しにしないように、できる限り確実にする必要があります。
ステージング セットアップでこれを実行する前に、明らかな問題がないか以下のコードを確認する必要があります (これは非常に高価です)。
問題
ソケットベースのアプリケーションを使用していますが、クライアントが CloseConnection リクエストを明示的に送信しないことがあります。また、IOException が発生しない場合もあります。これは、ブロッキングreadObject
呼び出しでスレッドを保持することによって発生します。
タイムアウト後に接続を閉じて、このスレッドを解放する必要があります。サーバーから新しいリクエストを受け取ると、タイムアウトが更新されます。
したがって、以下の3つの部分が表示されます
- 初期化中
- while(true) ループ内の readObject 呼び出し、およびスケジュールされたサービスのリセット
- インストリームの実際の終了
コード
Timer/TimerTask の代わりに ScheduledExecutorService を使用するようにアドバイスされました。
class StreamManager {
....
private ScheduledExecutorService activityTimeOut = Executors
.newSingleThreadScheduledExecutor();
private CloseConnectionOnTimeOut closeOnTimeOut = new CloseConnectionOnTimeOut();
....
public void initialize(Socket newClientSocket, ObjectInputStream newInputStream,
ObjectOutputStream newOutputStream, ThreadMonitor newThreadMonitor) {
....
closeOnTimeOut.setInputStream(myInputStream);
activityTimeOut.scheduleAtFixedRate(closeOnTimeOut, 0, Globals.INACTIVITY_TIME_OUT,
TimeUnit.MILLISECONDS);
}
public void run() {
....
while (true) {
try {
AMessageStrategy incomingCommand = (AMessageStrategy) myInputStream
.readObject();
activityTimeOut.shutdown();
activityTimeOut.scheduleAtFixedRate(closeOnTimeOut, 0,
Globals.INACTIVITY_TIME_OUT, TimeUnit.MILLISECONDS);
....
}
....
}
class CloseConnectionOnTimeOut implements Runnable {
private ObjectInputStream myInputStream;
public CloseConnectionOnTimeOut() {
}
public void setInputStream(ObjectInputStream myInputStream) {
this.myInputStream = myInputStream;
}
public void run() {
try {
myInputStream.close();
myOutputStream.close();
clientSocket.close();
log.info("Time out occured for client, closed connection forcefully.") ;
} catch (IOException e) {
e.printStackTrace();
log.fatal("Time out has occured, yet unable to clean up client connection. Keep a watch out on \"Size of clientStreamQ\"");
}
}
}
編集:小さなアプリケーションをテストしたところ、うまくいくようです。私はまだあなたのフィードバックが必要です。
再度編集:
アドバイスに従って、以下のコードを変更しました。
初期化中
private ScheduledExecutorService activityTimeOut = Executors
.newSingleThreadScheduledExecutor();
private Future<Void> timeoutTask ;
private CloseConnectionOnTimeOut closeOnTimeOut = new CloseConnectionOnTimeOut();
このコードを削除しました
closeOnTimeOut.setInputStream(myInputStream);
activityTimeOut.scheduleAtFixedRate(closeOnTimeOut, 0, Globals.INACTIVITY_TIME_OUT,
TimeUnit.MILLISECONDS);
readObject の前後に置換
timeoutTask = (Future<Void>) activityTimeOut.scheduleAtFixedRate(
closeOnTimeOut.setInputStream(myInputStream), 0,
Globals.INACTIVITY_TIME_OUT, TimeUnit.MILLISECONDS);
AMessageStrategy incomingCommand = (AMessageStrategy) myInputStream
.readObject();
timeoutTask.cancel(true) ;
クリーンアップ時
activityTimeOut.shutdown() ;