31
31
abstract class AbstractServerManager <T extends ModelControllerClient > implements ServerManager {
32
32
private static final Logger LOGGER = Logger .getLogger (AbstractServerManager .class );
33
33
34
- protected final ProcessHandle process ;
34
+ protected final ProcessHandle processHandle ;
35
+ private final Process process ;
35
36
final T client ;
36
37
private final boolean shutdownOnClose ;
37
38
private final DeploymentManager deploymentManager ;
38
39
private final AtomicBoolean closed ;
40
+ private volatile Thread shutdownWaitThread ;
39
41
40
- protected AbstractServerManager (final ProcessHandle process , final T client ,
42
+ protected AbstractServerManager (final Process process , final ProcessHandle processHandle , final T client ,
41
43
final boolean shutdownOnClose ) {
42
44
this .process = process ;
45
+ this .processHandle = processHandle ;
43
46
this .client = client ;
44
47
this .shutdownOnClose = shutdownOnClose ;
45
48
deploymentManager = DeploymentManager .create (client );
@@ -75,10 +78,10 @@ public String launchType() {
75
78
@ Override
76
79
public CompletableFuture <ServerManager > kill () {
77
80
final CompletableFuture <ServerManager > cf = new CompletableFuture <>();
78
- if (process != null && process .isAlive ()) {
81
+ if (processHandle != null && processHandle .isAlive ()) {
79
82
internalClose (false , false );
80
- if (process .destroyForcibly ()) {
81
- cf .thenCombine (process .onExit (), (serverManager , processHandle ) -> serverManager );
83
+ if (processHandle .destroyForcibly ()) {
84
+ cf .thenCombine (processHandle .onExit (), (serverManager , processHandle ) -> serverManager );
82
85
}
83
86
} else {
84
87
cf .complete (this );
@@ -96,16 +99,16 @@ public boolean waitFor(final long startupTimeout, final TimeUnit unit) throws In
96
99
break ;
97
100
}
98
101
timeout -= (System .currentTimeMillis () - before );
99
- if (process != null && !process .isAlive ()) {
102
+ if (processHandle != null && !processHandle .isAlive ()) {
100
103
throw new RuntimeException (
101
- String .format ("The process %d is no longer active." , process .pid ()));
104
+ String .format ("The process %d is no longer active." , processHandle .pid ()));
102
105
}
103
106
TimeUnit .MILLISECONDS .sleep (sleep );
104
107
timeout -= sleep ;
105
108
}
106
109
if (timeout <= 0 ) {
107
- if (process != null ) {
108
- process .destroy ();
110
+ if (processHandle != null ) {
111
+ processHandle .destroy ();
109
112
}
110
113
return false ;
111
114
}
@@ -162,7 +165,7 @@ public void shutdown(final long timeout) throws IOException {
162
165
public CompletableFuture <ServerManager > shutdownAsync (final long timeout ) {
163
166
checkState ();
164
167
final ServerManager serverManager = this ;
165
- if (process != null ) {
168
+ if (processHandle != null ) {
166
169
return CompletableFuture .supplyAsync (() -> {
167
170
try {
168
171
internalShutdown (client , timeout );
@@ -171,17 +174,17 @@ public CompletableFuture<ServerManager> shutdownAsync(final long timeout) {
171
174
}
172
175
return null ;
173
176
})
174
- .thenCombine (process .onExit (), (outcome , processHandle ) -> null )
177
+ .thenCombine (processHandle .onExit (), (outcome , processHandle ) -> null )
175
178
.handle ((ignore , error ) -> {
176
- if (error != null && process .isAlive ()) {
177
- if (process .destroyForcibly ()) {
179
+ if (error != null && processHandle .isAlive ()) {
180
+ if (processHandle .destroyForcibly ()) {
178
181
LOGGER .warnf (error ,
179
182
"Failed to shutdown the server. An attempt to destroy the process %d has been made, but it may still temporarily run in the background." ,
180
- process .pid ());
183
+ processHandle .pid ());
181
184
} else {
182
185
LOGGER .warnf (error ,
183
186
"Failed to shutdown server and destroy the process %d. The server may still be running in a process." ,
184
- process .pid ());
187
+ processHandle .pid ());
185
188
}
186
189
}
187
190
return serverManager ;
@@ -203,6 +206,29 @@ public CompletableFuture<ServerManager> shutdownAsync(final long timeout) {
203
206
});
204
207
}
205
208
209
+ @ Override
210
+ public int waitForTermination () throws InterruptedException {
211
+ checkState ();
212
+ shutdownWaitThread = Thread .currentThread ();
213
+ try {
214
+ if (process != null ) {
215
+ return process .waitFor ();
216
+ }
217
+ waitForShutdown (client );
218
+ return UNKNOWN_EXIT_STATUS ;
219
+ } finally {
220
+ shutdownWaitThread = null ;
221
+ }
222
+ }
223
+
224
+ @ Override
225
+ public int exitValue () throws IllegalStateException {
226
+ if (process != null ) {
227
+ return process .exitValue ();
228
+ }
229
+ return UNKNOWN_EXIT_STATUS ;
230
+ }
231
+
206
232
@ Override
207
233
public boolean isClosed () {
208
234
return closed .get ();
@@ -232,26 +258,35 @@ void internalClose(final boolean shutdownOnClose, final boolean waitForShutdown)
232
258
}
233
259
}
234
260
try {
235
- client .close ();
236
- } catch (IOException e ) {
237
- LOGGER .error ("Failed to close the client." , e );
261
+ // Interrupt the shutdown thread if it's still running
262
+ final Thread shutdownThread = shutdownWaitThread ;
263
+ if (shutdownThread != null ) {
264
+ LOGGER .debugf ("Interrupting shutdown thread %s." , shutdownThread .getName ());
265
+ shutdownThread .interrupt ();
266
+ }
267
+ } finally {
268
+ try {
269
+ client .close ();
270
+ } catch (IOException e ) {
271
+ LOGGER .error ("Failed to close the client." , e );
272
+ }
238
273
}
239
274
}
240
275
}
241
276
242
277
abstract void internalShutdown (ModelControllerClient client , long timeout ) throws IOException ;
243
278
244
279
private void waitForShutdown (final ModelControllerClient client ) {
245
- if (process != null ) {
280
+ if (processHandle != null ) {
246
281
try {
247
- process .onExit ()
282
+ processHandle .onExit ()
248
283
.get ();
249
284
} catch (InterruptedException | ExecutionException e ) {
250
- throw new RuntimeException (String .format ("Error waiting for process %d to exit." , process .pid ()), e );
285
+ throw new RuntimeException (String .format ("Error waiting for process %d to exit." , processHandle .pid ()), e );
251
286
}
252
287
} else {
253
288
// Wait for the server manager to finish shutting down
254
- while (ServerManager .isRunning (client )) {
289
+ while (! closed . get () && ServerManager .isRunning (client )) {
255
290
Thread .onSpinWait ();
256
291
}
257
292
}
0 commit comments