1616import java .util .concurrent .ScheduledThreadPoolExecutor ;
1717import java .util .concurrent .ThreadLocalRandom ;
1818import java .util .concurrent .TimeUnit ;
19+ import java .util .concurrent .locks .ReentrantLock ;
1920import java .util .logging .Level ;
2021
2122import static io .nats .NatsRunnerUtils .*;
@@ -25,6 +26,8 @@ public class ChaosRunner {
2526
2627 private static final String CR_LABEL = "ChaosRunner" ;
2728
29+ private static final ReentrantLock INSTANCE_LOCK = new ReentrantLock ();
30+ private static Thread APP_SHUTDOWN_HOOK_THREAD ;
2831 private static ChaosRunner INSTANCE ;
2932
3033 public final ChaosPrinter printer ;
@@ -282,35 +285,89 @@ public static ChaosRunner start(ChaosArguments a, ChaosPrinter printer) {
282285 NatsServerRunner .setDefaultOutputLevel (Level .SEVERE );
283286 final ChaosPrinter finalPrinter = printer == null ? getDefaultPrinter () : printer ;
284287
288+ INSTANCE_LOCK .lock ();
285289 try {
286290 INSTANCE = new ChaosRunner (a , finalPrinter );
287291 }
288292 catch (IOException e ) {
289293 finalPrinter .err (CR_LABEL , "Failed to start ChaosRunner" , e );
290294 System .exit (-1 );
291295 }
296+ finally {
297+ INSTANCE_LOCK .unlock ();
298+ }
292299
293- Runtime .getRuntime ().addShutdownHook (
294- new Thread ("app-shutdown-hook" ) {
295- @ Override
296- public void run () {
297- INSTANCE .shutdown ();
298- finalPrinter .out (CR_LABEL , "EXIT" );
299- }
300- });
300+ APP_SHUTDOWN_HOOK_THREAD = new Thread ("app-shutdown-hook" ) {
301+ @ Override
302+ public void run () {
303+ shutdownServers ();
304+ shutdownExecutor ();
305+ finalPrinter .out (CR_LABEL , "EXIT" );
306+ }
307+ };
308+
309+ Runtime .getRuntime ().addShutdownHook (APP_SHUTDOWN_HOOK_THREAD );
301310
302311 return INSTANCE ;
303312 }
304313
305- private void shutdown () {
314+ public static boolean isRunning () {
315+ INSTANCE_LOCK .lock ();
316+ try {
317+ return INSTANCE != null ;
318+ }
319+ finally {
320+ INSTANCE_LOCK .unlock ();
321+ }
322+ }
323+
324+ public static void shutdown () {
325+ INSTANCE_LOCK .lock ();
326+ try {
327+ removeShutdownHook ();
328+ shutdownExecutor ();
329+ shutdownServers ();
330+ }
331+ finally {
332+ INSTANCE_LOCK .unlock ();
333+ }
334+ }
335+
336+ public static void shutdownExecutor () {
337+ INSTANCE_LOCK .lock ();
306338 try {
307- for (NatsServerRunner runner : natsServerRunners ) {
308- try {
309- runner .close ();
339+ INSTANCE .executor .shutdown ();
340+ }
341+ finally {
342+ INSTANCE_LOCK .unlock ();
343+ }
344+ }
345+
346+ private static void removeShutdownHook () {
347+ INSTANCE_LOCK .lock ();
348+ try {
349+ if (APP_SHUTDOWN_HOOK_THREAD != null ) {
350+ Runtime .getRuntime ().removeShutdownHook (APP_SHUTDOWN_HOOK_THREAD );
351+ APP_SHUTDOWN_HOOK_THREAD = null ;
352+ }
353+ }
354+ finally {
355+ INSTANCE_LOCK .unlock ();
356+ }
357+ }
358+
359+ private static void shutdownServers () {
360+ INSTANCE_LOCK .lock ();
361+ try {
362+ if (INSTANCE != null ) {
363+ for (NatsServerRunner runner : INSTANCE .natsServerRunners ) {
364+ try { runner .close (); } catch (Exception ignore ) {}
310365 }
311- catch ( Exception ignore ) {}
366+ INSTANCE = null ;
312367 }
313368 }
314- catch (Exception ignore ) {}
369+ finally {
370+ INSTANCE_LOCK .unlock ();
371+ }
315372 }
316373}
0 commit comments