3737import org .apache .ignite .internal .util .typedef .internal .U ;
3838import org .apache .ignite .lang .IgniteInClosure ;
3939import org .apache .ignite .lang .IgniteProductVersion ;
40- import org .apache .ignite .testframework .GridTestUtils ;
4140import org .apache .ignite .testframework .junits .multijvm .IgniteNodeRunner ;
4241import org .jetbrains .annotations .NotNull ;
4342import 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