views:

1463

answers:

2

I'm currently using Quartz Scheduler as a replacement for Cron on our Windows 2003 Server Box. I have two specific Jobs that needed to be started in a new VM, so I'm using the ProcessBuilder object in Java 5 to get my "Process" object. The problem I'm running into is when our Quartz Scheduler JVM stops, the 2 jobs in separate JVM's keep going.

        Process process = Runtime.getRuntime().exec(command);
        try
        {
            while (true)
            {

                Thread thread1 = new Thread(new ReaderThread(process.getInputStream()));
                Thread thread2 = new Thread(new ReaderThread(process.getErrorStream()));

                thread1.start();
                thread2.start();

                thread1.join();
                thread2.join();

Is there a way to Kill these threads when the parent JVM associated with my Quartz Scheduler dies? Even if I knew of a way to kill them from a different process manually, I could figure out how to do it through Quartz.

Thank you in advance

+2  A: 

You can use a shutdown hook.

class ProcessKiller extends Thread {
  private Process process = null;
  public ProcessKiller(Process p) {
    this.process = p;
  }


  public void run() {
    try {
      p.destroy();
    } catch ( Throwable e ) {}
  }
}

Runtime.getRuntime().addShutdownHook( new ProcessKiller( process ));
Clint
+3  A: 

If the Quartz JVM exits normally, you can just destroy the processes in a finally block. This may obviate the need for a shutdown hook. A shutdown hook may not execute on abnormal JVM termination. The Runtime javadocs state,

If the virtual machine aborts then no guarantee can be made about whether or not any shutdown hooks will be run.

Here is the modified code (I've added a timeout and a method call to wait for the process to exit)

    private static final long TIMEOUT_MS = 60000;
    Process process = Runtime.getRuntime().exec(command);
    try
    {
        while (true)
        {

            Thread thread1 = new Thread(new ReaderThread(process.getInputStream()));
            Thread thread2 = new Thread(new ReaderThread(process.getErrorStream()));

            thread1.start();
            thread2.start();

            process.waitFor();
            thread1.join(TIMEOUT_MS);
            thread2.join(TIMEOUT_MS);
            ...
        }
    } finally {
        process.destroy();
    }

In general I've found that processes spawned from Java are clunky and not very resilient, as you've probably discovered given the need for the two ReaderThreads. In particular, subprocesses that freeze up can be difficult to terminate from within Java. As a last resort, you can use the Windows "taskkill" command to nuke the process from a command line or a scheduled task:

taskkill /IM MySpawnedProcess.exe

ThisIsTheDave