Skip to content

Commit eeefdfc

Browse files
committed
chaos runner shutdown improvements
1 parent 2c60a5d commit eeefdfc

File tree

3 files changed

+166
-15
lines changed

3 files changed

+166
-15
lines changed

chaos-runner/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ plugins {
1313
id 'signing'
1414
}
1515

16-
def jarVersion = "0.0.6"
16+
def jarVersion = "0.0.7"
1717
group = 'io.synadia'
1818

1919
def isMerge = System.getenv("BUILD_EVENT") == "push"
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Copyright (c) 2025 Synadia Communications Inc. All Rights Reserved.
2+
// See LICENSE and NOTICE file for details.
3+
4+
package io.synadia.examples;
5+
6+
import io.synadia.chaos.ChaosArguments;
7+
import io.synadia.chaos.ChaosRunner;
8+
9+
import java.io.BufferedReader;
10+
import java.io.IOException;
11+
import java.io.InputStream;
12+
import java.io.InputStreamReader;
13+
import java.net.URL;
14+
15+
import static io.synadia.chaos.ChaosUtils.out;
16+
17+
public class ChaosRunnerShutdown {
18+
19+
public static void main(String[] args) throws Exception {
20+
ChaosArguments arguments = new ChaosArguments()
21+
.servers(3)
22+
.workDirectory("C:\\temp\\chaos-runner")
23+
.serverNamePrefix("cr-shutdown-server")
24+
.clusterName("cr-shutdown-cluster")
25+
.delay(30_000)
26+
.initialDelay(30_000)
27+
.downTime(30_000);
28+
29+
ChaosRunner runner = ChaosRunner.start(arguments);
30+
31+
// just give the servers a little time to be ready be first connect
32+
Thread.sleep(1000);
33+
34+
String[] urls = runner.getConnectionUrls();
35+
out("Connection Urls");
36+
for (String url : urls) {
37+
out(" ", url);
38+
}
39+
40+
int[] ports = runner.getConnectionPorts();
41+
int[] monitorPorts = runner.getMonitorPorts();
42+
43+
Thread.sleep(1000);
44+
out("H RUNNING", ChaosRunner.isRunning());
45+
for (int i = 0; i < monitorPorts.length; i++) {
46+
int port = ports[i];
47+
int mport = monitorPorts[i];
48+
String hz = readHealthz(monitorPorts[i]);
49+
out("H", port + "/" + mport, hz);
50+
}
51+
52+
ChaosRunner.shutdown();
53+
54+
Thread.sleep(1000);
55+
out("Z RUNNING", ChaosRunner.isRunning());
56+
for (int i = 0; i < monitorPorts.length; i++) {
57+
int port = ports[i];
58+
int mport = monitorPorts[i];
59+
String hz = readHealthz(monitorPorts[i]);
60+
out("Z", port + "/" + mport, hz);
61+
}
62+
}
63+
64+
private static String readHealthz(int port) {
65+
return readEndpoint(port, "healthz");
66+
}
67+
68+
private static String readEndpoint(int port, String endpoint) {
69+
String sUrl = "http://localhost:" + port + "/" + endpoint;
70+
try {
71+
URL url = new URL(sUrl);
72+
InputStream inputStream = url.openStream();
73+
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
74+
75+
boolean first = true;
76+
String line;
77+
StringBuilder content = new StringBuilder();
78+
while ((line = reader.readLine()) != null) {
79+
if (first) {
80+
first = false;
81+
}
82+
else {
83+
content.append(System.lineSeparator());
84+
}
85+
content.append(line);
86+
}
87+
reader.close();
88+
return content.toString().trim();
89+
}
90+
catch (IOException e) {
91+
return e.getMessage();
92+
}
93+
}
94+
}

chaos-runner/src/main/java/io/synadia/chaos/ChaosRunner.java

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import java.util.concurrent.ScheduledThreadPoolExecutor;
1717
import java.util.concurrent.ThreadLocalRandom;
1818
import java.util.concurrent.TimeUnit;
19+
import java.util.concurrent.locks.ReentrantLock;
1920
import java.util.logging.Level;
2021

2122
import 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

Comments
 (0)