Skip to content

Commit 3f31281

Browse files
authored
IGNITE-27879 Add parent process listener to IgniteCompatibilityNodeRunner (#12756)
1 parent fda3419 commit 3f31281

File tree

1 file changed

+40
-5
lines changed

1 file changed

+40
-5
lines changed

modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityNodeRunner.java

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
import org.apache.ignite.internal.util.typedef.internal.U;
3838
import org.apache.ignite.lang.IgniteInClosure;
3939
import org.apache.ignite.lang.IgniteProductVersion;
40-
import org.apache.ignite.testframework.GridTestUtils;
4140
import org.apache.ignite.testframework.junits.multijvm.IgniteNodeRunner;
4241
import org.jetbrains.annotations.NotNull;
4342
import org.jetbrains.annotations.Nullable;
@@ -79,6 +78,8 @@ public static void main(String[] args) throws Exception {
7978
" [optional/path/to/closure/file]");
8079
}
8180

81+
startParentPipeWatcher();
82+
8283
final Thread watchdog = delayedDumpClasspath();
8384

8485
IgniteConfiguration cfg = CompatibilityTestsFacade.getConfiguration();
@@ -96,16 +97,13 @@ public static void main(String[] args) throws Exception {
9697
cfg.setIgniteInstanceName(args[1]);
9798
cfg.setNodeId(nodeId);
9899

99-
final Ignite ignite = Ignition.start(cfg);
100+
ignite = Ignition.start(cfg);
100101

101102
assert ignite.cluster().node(syncNodeId) != null : "Node has not joined [id=" + nodeId + "]";
102103

103104
assert ignite.cluster().localNode().version().compareToIgnoreTimestamp(expNodeVer) == 0 : "Node is of unexpected " +
104105
"version: [act=" + ignite.cluster().localNode().version() + ", exp=" + expNodeVer + ']';
105106

106-
// It needs to set private static field 'ignite' of the IgniteNodeRunner class via reflection
107-
GridTestUtils.setFieldValue(new IgniteNodeRunner(), "ignite", ignite);
108-
109107
if (args.length == 6) {
110108
IgniteInClosure<Ignite> clo = readClosureFromFileAndDelete(args[5]);
111109

@@ -127,6 +125,43 @@ public static void main(String[] args) throws Exception {
127125
}
128126
}
129127

128+
/**
129+
* Checks that parent process is alive.
130+
*
131+
* <p>We listen on {@code System.in} because this compatibility node is started by the parent JVM via
132+
* {@link ProcessBuilder}, where {@code System.in} is a pipe from the parent. When the parent process exits,
133+
* the write-end of the pipe is closed and {@code System.in.read()} returns EOF. We treat this as a signal
134+
* to stop Ignite and terminate the process.</p>
135+
*/
136+
private static void startParentPipeWatcher() {
137+
Thread thread = new Thread(() -> {
138+
try {
139+
while (System.in.read() != -1) {
140+
// No-op
141+
}
142+
}
143+
catch (IOException e) {
144+
X.println("Failed to read parent stdin pipe, stopping compatibility node: " + e);
145+
}
146+
147+
X.println("Parent JVM stdin pipe is closed, stopping compatibility node");
148+
149+
try {
150+
if (ignite != null)
151+
Ignition.stop(ignite.name(), true);
152+
}
153+
catch (Throwable e) {
154+
X.println("Failed to stop compatibility node after parent pipe closure: " + e);
155+
}
156+
finally {
157+
System.exit(0);
158+
}
159+
}, "compatibility-parent-pipe-watcher");
160+
161+
thread.setDaemon(true);
162+
thread.start();
163+
}
164+
130165
/**
131166
* Starts background watchdog thread which will dump main thread stacktrace and classpath dump if main thread
132167
* will not respond with node startup finished.

0 commit comments

Comments
 (0)