brettwooldridge / NuProcess

Low-overhead, non-blocking I/O, external Process implementation for Java
Apache License 2.0
710 stars 84 forks source link

NPE on process start on Linux #145

Closed gagarski closed 5 months ago

gagarski commented 1 year ago

Under some undetermined circumstances, I get NPE when starting a process with quite straightforward code:

2023-06-20 09:29:58.390  WARN - c.z.n.internal.BasePosixProcess Exception thrown from handler
 java.lang.NullPointerException: Cannot invoke "com.zaxxer.nuprocess.NuProcessHandler.onStart(com.zaxxer.nuprocess.NuProcess)" because "this.processHandler" is null
    at com.zaxxer.nuprocess.internal.BasePosixProcess.callStart(BasePosixProcess.java:587)
    at com.zaxxer.nuprocess.linux.LinuxProcess.start(LinuxProcess.java:80)
    at com.zaxxer.nuprocess.linux.LinProcessFactory.createProcess(LinProcessFactory.java:40)
    at com.zaxxer.nuprocess.NuProcessBuilder.start(NuProcessBuilder.java:260)
    at com.example.process.manager.linux.PsProcessTable.ps(PsProcessTable.java:66)
        ...

The handler set is pretty much straightforward:

    private static class PsHandler extends NuAbstractProcessHandler {
        private final ByteArrayOutputStream output = new ByteArrayOutputStream();

       // No other handlers

        @Override
        public void onStdout(ByteBuffer buffer, boolean closed) {
            synchronized (this) {
                // Some logic to grab the output
            }
        }

        public synchronized String getStdOut() {
            if (!closed) {
                throw new IllegalStateException("Reading ps output is not done yet");
            }
            return output.toString(Charset.defaultCharset());
        }
    }

and the executing code is pretty much straightforward:

    public static ParsedOutput run() {
        var bld = new NuProcessBuilder(CLI);
        var handler = new PsHandler();
        bld.setProcessListener(handler);
        var ps = bld.start();
        try {
            ps.waitFor(0, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            throw new IllegalStateException("ps was interrupted");
        }
        // Just parsing what we've just grabbed
        return new PsProcessTable(handler.getStdOut());
    }

After adding some debug log records, I noticed that onStart is being called after onExit, which is OK according to the javadoc:

Note that this method is called at some point after the process is spawned. It is possible for other methods (even onExit(int)) to be called first. If you need a guarantee that no other methods will be called first, use onPreStart(NuProcess) instead.

The problem is that I get this warning even though I am not overriding onStart (otherwise, I'd put my logic to onPreStart callback, as suggested), BasePosixProcess just removes ProcessHandler on exit logic. This actually makes onStart being called not "after onExit" but actually never. And there is nothing I can do on client side to avoid this warning in my logs.

avrecko commented 5 months ago

I had the same problem. See #149.

gagarski commented 5 months ago

Likely fixed in #149