drain-java
drain-java copied to clipboard
Replace JVM file watcher by alternatives that are not affected by filesystems boundaries
The watchservice of the JVM suffers from a few drawbacks regarding its integration with the OS. In Linux in particular events of bind mounts are not received.
Let's investigate alternative, in particular the gradle native integration : https://github.com/gradle/native-platform
+ implementation("net.rubygrapefruit:file-events:0.22")
+ implementation("net.rubygrapefruit:native-platform:0.22")
Currently file watching capabilities just appeared in a 0.22 milestone, unfortunately this is not completely released (platform specific native libraries are not published on bintray (for the published milestone)).
To follow https://github.com/gradle/native-platform/releases
However native-platform:0.21
is available on it's possible to play with some api like the terminal or files, e.g. :
try {
Terminals terminals = Native.get(Terminals.class);
var isTerminal = terminals.withAnsiOutput().isTerminal(Output.Stdout);
if (isTerminal) {
var terminal = terminals.withAnsiOutput().getTerminal(Output.Stdout);
terminal.write("Hello");
SECONDS.sleep(5);
terminal.cursorStartOfLine()
.clearToEndOfLine()
.bold().write("Bold hello")
.reset();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
Gradle's native-platform may not be a good fit after all.
Gradle's native-platform uses macOs's fsevents to handle file events, which does not pickup all file changes.
While looking at macOs tail
source code I found that it is based on BSD's kqueue and this mechanisms report correctly single file changes.
This finding has been confirmed with the tool fswatch (it implements various way to watch files ; on macOS: fsevents, kqueue, or polling).
Reference issues :
- https://github.com/gradle/native-platform/issues/269
- https://github.com/emcrisostomo/fswatch/issues/265
Another idea would be to use JDK16's foreign linker incubator API to leverage kqueue (if JDK 16 is available). Or write a JNI / C code.