3

以下のコードでサービス(プロセス)を起動しています。私の問題は次のとおりです。

  • プロセスの出力を読み取って、プロセスが開始されたことを確認する必要があります
  • それが始まったら、私は戻って、すべてが大丈夫です
  • なんらかの理由で開始されない場合、プロセスは何も出力せずにハングするため、whileは永久にブロックされます

期待される文字列が得られない場合に、メソッドを正常に終了する方法はありますか?

ps:Futureとgetのタイムアウトでそれを行うことができましたが、もっと良い方法があるかもしれないと思いました。

public boolean startService() {
    try {
        ProcessBuilder pb = new ProcessBuilder("service.exe");
        pb.directory(new File("C:/serviceFolder/"));
        pb.redirectErrorStream(true);
        Process p = pb.start();
        BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
        String line;
        while ((line = reader.readLine()) != null) {
            if (line.toLowerCase().contains("started")) {
                return true;
            }
        }
        return false; //I never get there when it fails
    } catch (IOException e) {
        throw new RuntimeException("Could not start the service.exe process", e);
    }        
}
4

3 に答える 3

2

サービスコードを変更できる場合は、開始できない場合にハングしないように変更することをお勧めします。終了してエラーメッセージをログに記録する必要があります。このようにして、Javaコードはそのまま機能します。

できない場合は、タイムアウトを設定する以外に方法はありません。Javaコードには、何が起こっているのかを知る手段がないためです。

もちろん、サービスを変更できる場合は、PIDファイル、エラーログメッセージなど、プロセスの標準出力/エラー以外の出力を監視することもできます。たとえば、サブプロセスがすでにPIDファイルを作成している場合、標準入力の代わりにこのファイルのチェックをスケジュールできますが、実際には同じ概念であり、より適切で単純なコードを使用するために異なる方法で適用されます。

于 2012-09-27T12:57:44.113 に答える
0

このようなものが機能するはずです。基本的に、別のスレッドでサービスを開始しTimer、一定期間後にサービスを中断するを作成します。タイマータスクはDaemonなので、終了する必要がある場合にプロセスを中断しないようにする必要があることに注意してください。

reader.readLine()明らかに、これは割り込みを消費して破棄する場合は機能しません。

private static class ServiceRunner implements Runnable {
  // Am I running?
  volatile boolean running = true;
  // My thread.
  volatile Thread thread = Thread.currentThread();

  @Override
  public void run() {
    // Start a timer.
    Timer timer = new Timer("Wait for ServiceRunner to finish.", true);
    // Fire it after 2 seconds.
    timer.schedule(new StopTask(), 2000);
    try {
      // Start the service.
      startService();
    } finally {
      // No longer running.
      running = false;
    }
  }

  class StopTask extends TimerTask {

    @Override
    public void run() {
      if (running) {
        // Interrupt the service runner.
        thread.interrupt();
      }
    }
  }

  public boolean startService() {
    try {
      ProcessBuilder pb = new ProcessBuilder("service.exe");
      pb.directory(new File("C:/serviceFolder/"));
      pb.redirectErrorStream(true);
      Process p = pb.start();
      BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
      String line;
      while ((line = reader.readLine()) != null) {
        if (line.toLowerCase().contains("started")) {
          return true;
        }
      }
      return false; //I never get there when it fails
    } catch (IOException e) {
      throw new RuntimeException("Could not start the service.exe process", e);
    }
  }
}

私はこのコードをテストしていませんが、動作するはずです。

サービスが開始されたかどうかを保持するために調整を行う必要があります。

于 2012-09-27T13:38:46.387 に答える
0

このFuture#getアプローチが好ましいようです。今後の参考のために、次のようにコードを変更しました。

public boolean startService() {

    Callable<Boolean> start = new Callable<Boolean>() {
        @Override
        public Boolean call() throws Exception {
            ProcessBuilder pb = new ProcessBuilder("service.exe");
            pb.directory(new File("C:/serviceFolder/"));
            pb.redirectErrorStream(true);
            Process p = pb.start();
            BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.toLowerCase().contains("started")) {
                    return true;
                }
            }
            return false;
        }
    };

    ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<Boolean> future = executor.submit(start);

    try {
        return future.get(1, TimeUnit.SECONDS);
    } catch (InterruptedException ignore) {
        Thread.currentThread().interrupt();
        return false;
    } catch (ExecutionException | TimeoutException e) {
        logger.error("Could not start service", e);
        return false;
    } finally {
        executor.shutdownNow();
    }
}
于 2012-09-27T14:38:50.393 に答える