Skip to content

Commit c690301

Browse files
fix: prevent duplicate shutdown hooks and replace e.printStackTrace() in CassandraConnector (#1183)
Two issues fixed: 1. prepareSession() called registerShutdownHook() on every invocation. If getSession() triggered re-preparation (stale/closed session), multiple hooks were registered for the same operation. Added a shutdownHookRegistered boolean guard to ensure exactly one hook is registered for the lifetime of the process. 2. e.printStackTrace() in the catch block sent stack traces to stderr without context. Replaced with TelemetryManager.error() for consistent, structured logging. 3. close() now iterates sessions individually with per-session error handling so a failure on one session does not abort closing others, and clears the map after shutdown. Co-authored-by: Claude <claude@anthropic.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 6c2a9a5 commit c690301

File tree

1 file changed

+24
-7
lines changed

1 file changed

+24
-7
lines changed

platform-core/cassandra-connector/src/main/java/org/sunbird/cassandra/CassandraConnector.java

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ public class CassandraConnector {
2222
/** Cassandra Session Map. */
2323
private static Map<String, Session> sessionMap = new HashMap<String, Session>();
2424

25+
/** Guard to prevent registering duplicate JVM shutdown hooks. */
26+
private static boolean shutdownHookRegistered = false;
27+
2528
static {
2629
if (Platform.getBoolean("service.db.cassandra.enabled", true))
2730
prepareSession("lp", getConsistencyLevel("lp"));
@@ -77,9 +80,11 @@ private static void prepareSession(String sessionKey, ConsistencyLevel level) {
7780
.build().connect());
7881
}
7982

80-
registerShutdownHook();
83+
if (!shutdownHookRegistered) {
84+
registerShutdownHook();
85+
shutdownHookRegistered = true;
86+
}
8187
} catch (Exception e) {
82-
e.printStackTrace();
8388
TelemetryManager.error("Error! While Loading Cassandra Properties." + e.getMessage(), e);
8489
}
8590
}
@@ -129,21 +134,33 @@ private static List<InetSocketAddress> getSocketAddress(List<String> hosts) {
129134
}
130135

131136
/**
132-
* Close connection with the cluster.
133-
*
137+
* Close all Cassandra sessions gracefully.
138+
* Each session is closed individually so a failure in one does not
139+
* prevent closing the others.
134140
*/
135141
public static void close() {
136-
sessionMap.entrySet().stream().forEach(stream -> stream.getValue().close());
142+
sessionMap.forEach((key, session) -> {
143+
if (session != null && !session.isClosed()) {
144+
try {
145+
session.close();
146+
} catch (Exception e) {
147+
TelemetryManager.error("Error closing Cassandra session for key: " + key + " — " + e.getMessage(), e);
148+
}
149+
}
150+
});
151+
sessionMap.clear();
137152
}
138153

139154
/**
140-
* Register JVM shutdown hook to close cassandra open session.
155+
* Register a single JVM shutdown hook to close all open Cassandra sessions.
156+
* Protected by shutdownHookRegistered so it is called only once even when
157+
* prepareSession() is invoked multiple times.
141158
*/
142159
private static void registerShutdownHook() {
143160
Runtime.getRuntime().addShutdownHook(new Thread() {
144161
@Override
145162
public void run() {
146-
TelemetryManager.log("Shutting down Cassandra connector session");
163+
TelemetryManager.log("Shutting down Cassandra connector — closing all sessions");
147164
CassandraConnector.close();
148165
}
149166
});

0 commit comments

Comments
 (0)