On Windows, I am creating subprocess via java.lang.ProcessBuilder. On trying to cleanup the process and its standard output log file if my caller function is interrupted, I get error "The process cannot access the file because it is being used by another process". I am ensuring that I destroy the subprocess first and then delete the logfile.
Question - Are there any best practices when cleaning up processes and log files that are platform agnostic?
Here is a reproducible example for Windows.
Below snippet is creating a subprocess.
public class UndeletableFileExample {
public static void func() throws IOException {
ProcessBuilder pb = null;
Path stdout = null;
Process p = null;
long bufferTimeSecs = 30L;
try {
stdout = Files.createTempFile("example", ".log");
pb = new ProcessBuilder("loop.cmd");
pb.redirectErrorStream(true);
pb.redirectOutput(stdout.toFile());
p = pb.start();
p.waitFor(bufferTimeSecs, TimeUnit.SECONDS);
p.destroy();
p.waitFor(bufferTimeSecs, TimeUnit.SECONDS);
p.destroyForcibly();
String out = Files.readString(stdout);
int exitcode = p.exitValue();
if(exitcode != 0) {
throw new RuntimeException("Exited with code " + exitcode);
}
System.out.println(out);
}
catch(InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("interrupted!");
}
finally {
if(p != null) {
p = p.destroyForcibly();
while(p.isAlive()); // Is this while loop a potential problem?
System.out.println(p.exitValue());
}
if(stdout != null) {
Files.delete(stdout);
}
}
}
}
Below snippet is for the for-loop file "loop.cmd". It will print numbers from 1 till 1e5. This takes a good 20-30 seconds on my machine.
FOR /L %%i IN (1,1,100000) DO echo %%i
Below snippet is for the main program that does the simulation.
public class Demo {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread() {
@Override
public void run() {
try {
UndeletableFileExample.func();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
t.start();
Thread.sleep(2000L);
t.interrupt();
t.join();
}
}
I also have access to a MacOS machine. I didn't encounter any problem there in cleaning up the process and the logfile on a thread interrupt.
The loop example for MacOS changes to -
for i in `seq 1 1000000`; do echo $i; done
The exact error on Windows is as follows -
Exception in thread "Thread-0" java.lang.RuntimeException: java.nio.file.FileSystemException: <...>\example1234.log: The process cannot access the file because it is being used by another process.