Java Apache Commons Exec 看门狗和 Windows cmd.exe 问题

问题描述 投票:0回答:1

我正在尝试为我的程序使用看门狗,但如果我使用 cmd.exe 启动它,它就不起作用。如果进程是本机启动的(没有 cmd.exe),看门狗会终止进程,但如果程序是用 cmd.exe 启动的,它什么也不做。

工作代码示例:

        CommandLine cmd1 = CommandLine.parse("mysql");

        ExecuteWatchdog watchdog = new ExecuteWatchdog(3 * 1000); // wait for 3 sec

        Executor executor = new DefaultExecutor();

        executor.setWatchdog(watchdog);


        try {

            executor.execute(cmd1);

        } catch (IOException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        } 

        System.out.println("DONE!");

将命令更改为此,将永远阻塞线程('mysql' 等待用户输入):

CommandLine cmd1 = CommandLine.parse("cmd /C start /wait cmd.exe /C 'mysql'");

你有什么想法,如何解决这个问题? “mysql”命令应在新的 cmd.exe 窗口中运行。

java windows watchdog apache-commons-exec
1个回答
0
投票

我通过扩展 ExecuteWatchdog 解决了这个问题;即:

static class DestroyDescendantsExecutorWatchDog extends ExecuteWatchdog {
    private Process process = null;

    /**
     * Creates a new watchdog with a given timeout.
     *
     * @param timeout the timeout for the process in milliseconds. It must be
     *                greater than 0 or 'INFINITE_TIMEOUT'
     */
    public DestroyDescendantsExecutorWatchDog(long timeout) {
        super(timeout);
    }

    /**
     * Overridden to capture and store the process to monitor.
     * @param processToMonitor
     *            the process to monitor. It cannot be {@code null}
     */
    @Override
    public synchronized void start(Process processToMonitor) {
        super.start(processToMonitor);
        process = processToMonitor;
    }


    /**
     * Overridden to clean up the process to monitor state as we stop monitoring.
     */
    @Override
    public synchronized void stop() {
        super.stop();
        process = null;
    }

    /**
     * Overrides the default behavior to collect the descendants and kill them as well.
     * @param w the watchdog that timed out.
     */
    @Override
    public synchronized void timeoutOccured(Watchdog w) {
        // if the process is defined
        if (process != null) {
            boolean isProcessTerminated = true;
            try {
                // We must check if the process was not stopped before being here
                process.exitValue();
            } catch (final IllegalThreadStateException itse) {
                // the process is not terminated, if this is really
                // a timeout and not a manual stop then destroy it.
                if (isWatching()) {
                    isProcessTerminated = false;
                }
            }
            // if we haven't already started terminating the process
            if (!isProcessTerminated) {
                // get all the descendants before you destroy the root process
                Stream<ProcessHandle> descendants = process.toHandle().descendants();
                // now go destroy the root process
                super.timeoutOccured(w);
                // follow up by destroying the descendants as well
                descendants.forEach(descendant -> {
                    try {
                        descendant.destroy();
                    } catch (Exception e) {
                        log.warn("pid={};info={}; Could not destroy descendant", descendant.pid(), descendant.info(), e);
                    }
                });
                // no longer watching this process as it's destroyed
                process = null;
            }
        }
    }
}

真正的魔法是连同根进程一起摧毁后代。

我有一个单元测试表明基本上是这样做的:

bash“script.sh” 其中 script.sh 只是一个“睡眠 5”

在使用 ExecuteWatchdog 之前,ExecuteWatchdog 会使进程超时,退出代码为 143,但仅在 5 秒后。在将 ExecuteWatchdog 替换为 DestroyDescendantsExecutorWatchDog 并设置 5 毫秒超时后,单元测试几乎立即退出并返回预期的代码 143。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.