DEV Community

harithay
harithay

Posted on • Updated on

Introduction to Java ProcessHandle

This is a quick introduction to application of Java ProcessHandle through a use case.

Background:

I developed a website call xconvert.com. It uses a range of free software to process user requests. To put it simply, it is an orchestrator for bunch of free opensource software such as FFMPEG. While there are libraries that allows me to use most of these software directly from my Java application (Mostly though JNI), they are always bit outdated or unstable. I, being a brave programmer, choose to use Java ProcessBuilder and Process to execute programs such as FFMPEG with arguments. Managing of processes spawn like that is bit chaotic. Until the release of Java 9, I had a code that mainly uses Runtime.getRuntime().exec("ps aux...") to find and kill processes that hangs or exceed time limit. I had quite a bit of code, an ugly code, written to manage processes. I got really exited when I came across Java 9 ProcessHandle interface. It exposes many information about processes running on a machine (specifically when used in Linux systems) which I could use to do a major cleanup.

About ProcessHandle:

Java ProcessHandle provides a interface to native processes. Interface allows reading information about processes, such as checking whether a process is alive or invoking simple operations on those process such as killing it.

Use case:

I will walk you though following use case which I used to explain some of the useful part of the ProcessHandle interface.

  1. Get all running processes on the system
  2. Filter ffmpeg processes that meets a certain criteria
    1. Check if they are running
    2. Check if they are running for more than 4 hours
    3. Check if input file fed to ffmpeg is deleted
  3. Kill all hanged ffmpeg processes

Step 1: Finding all processes

Stream<ProcessHandle> allProcesses = ProcessHandle.allProcesses();
Enter fullscreen mode Exit fullscreen mode

Step 2: Filter processes

Stream<ProcessHandle> toDeleteProcessHandles = allProcesses.filter(processHandle -> {
    // Check if process is alive
    if(processHandle.isAlive()){
        Info info = processHandle.info();
        String executableWithPath = info.command().orElse(null);
        // Check if this is an ffmpeg instant
        if(executableWithPath != null && executableWithPath.endsWith("ffmpeg")){
            // Check if they are running for more than 4 hours
            if(Duration.between(Instant.now(), info.startInstant().get()).toHours() > 4){

                // Check if input file fed on to ffmpeg is deleted
                String[] arguments = info.arguments().orElse(null);
                String inputFile = Arrays.stream(arguments).filter(arg -> arg.startsWith("/home/username/content/input")).findFirst().orElse(null);
                if(inputFile != null && !Files.exists(Paths.get(inputFile))){
                    return true;
                }
            }
        }
    }
    return false;
});
Enter fullscreen mode Exit fullscreen mode

Step 3: Kill hanged processes

toDeleteProcessHandles.forEach(processHandle -> processHandle.destroy());
Enter fullscreen mode Exit fullscreen mode

This interface combined with Stream API allow writing concise code. You may have noticed that I used orElse(null) in some places. Which is from Java Optional class introduced in Java 1.8 with Stream API. You can further clean up this code by using methods such is isPresent() on Optional class instead of clustering with someVariable != null && doSomethingWithSomeVariable inside if expressions checks.

Another useful static method on this class is

ProcessHandle handle = ProcessHandle.of(long pid);
Enter fullscreen mode Exit fullscreen mode

This is useful when you start a process using ProcessBuilder or have a Java Process object. Java Process object (Java 9+) exposes PID of a process though someProcess.pid(). Which you can use with ProcessHandle.of() to keep track of a process.

You could find more about ProcessHandle and ProcessHandle.Info by reading their documentation.

This very code is in action every time someone convert a video or compresses a jpeg on XConvert.

Thank you for reading. You are welcome to ask questions or give a feedback.

Top comments (0)