Skip to content

Commit 1287a9c

Browse files
committed
Connection error handling in the pool
1 parent 558b1e9 commit 1287a9c

3 files changed

Lines changed: 64 additions & 9 deletions

File tree

core/src/main/java/me/zort/sqllib/SQLConnectionPool.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public SQLConnectionPool(@NotNull SQLConnectionBuilder from, @NotNull Options po
7171
public Resource getResource() throws SQLException {
7272
freeConnections.removeIf(SQLPooledConnection::expired);
7373
SQLPooledConnection polled = freeConnections.poll();
74-
if (polled == null && usedConnections.size() < maxConnections) {
74+
if (polled == null && size() < maxConnections) {
7575
polled = establishObject();
7676
} else if(polled == null) {
7777

@@ -83,7 +83,7 @@ public Resource getResource() throws SQLException {
8383
while ((polled = freeConnections.poll()) == null) {
8484
if (System.currentTimeMillis() - start > borrowObjectTimeout) {
8585
throw new SQLException("Timeout while waiting for a connection.");
86-
} else if(usedConnections.size() < maxConnections) {
86+
} else if(size() < maxConnections) {
8787
polled = establishObject();
8888
break;
8989
}
@@ -99,6 +99,17 @@ private SQLPooledConnection establishObject() throws SQLException {
9999

100100
SQLException error = polled.connection.getLastError();
101101
if (error != null) throw error;
102+
103+
if (polled.connection instanceof SQLDatabaseConnectionImpl) {
104+
((SQLDatabaseConnectionImpl) polled.connection).addErrorHandler(code -> {
105+
// Remove the connection from the pool and disconnect
106+
// on fatal errors.
107+
freeConnections.remove(polled);
108+
usedConnections.remove(polled);
109+
polled.connection.disconnect();
110+
});
111+
}
112+
102113
return polled;
103114
}
104115

core/src/main/java/me/zort/sqllib/SQLDatabaseConnectionImpl.java

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
import java.util.concurrent.CopyOnWriteArrayList;
4141
import java.util.logging.Logger;
4242

43+
import static me.zort.sqllib.util.ExceptionsUtility.runCatching;
44+
4345
/**
4446
* Main database client object implementation.
4547
* This class is responsible for handling requests from query
@@ -52,11 +54,11 @@ public class SQLDatabaseConnectionImpl extends SQLDatabaseConnection {
5254

5355
// --***-- Default Constants --***--
5456

55-
public static boolean DEFAULT_AUTO_RECONNECT = true;
56-
public static boolean DEFAULT_DEBUG = false;
57-
public static boolean DEFAULT_LOG_SQL_ERRORS = true;
58-
public static NamingStrategy DEFAULT_NAMING_STRATEGY = new DefaultNamingStrategy();
59-
public static Gson DEFAULT_GSON = Defaults.DEFAULT_GSON;
57+
public static final boolean DEFAULT_AUTO_RECONNECT = true;
58+
public static final boolean DEFAULT_DEBUG = false;
59+
public static final boolean DEFAULT_LOG_SQL_ERRORS = true;
60+
public static final NamingStrategy DEFAULT_NAMING_STRATEGY = new DefaultNamingStrategy();
61+
public static final Gson DEFAULT_GSON = Defaults.DEFAULT_GSON;
6062

6163
// --***-- Options & Utilities --***--
6264

@@ -66,6 +68,7 @@ public class SQLDatabaseConnectionImpl extends SQLDatabaseConnection {
6668
private final transient StatementMappingFactory mappingFactory;
6769
@ApiStatus.Experimental
6870
private final transient StatementMappingResultAdapter mappingResultAdapter;
71+
private final transient List<ErrorStateObserver> errorStateHandlers;
6972
private transient ObjectMapper objectMapper;
7073
@Setter
7174
private transient Logger logger;
@@ -101,6 +104,7 @@ public SQLDatabaseConnectionImpl(SQLConnectionFactory connectionFactory, @Nullab
101104
this.objectMapper = new DefaultObjectMapper(this);
102105
this.mappingFactory = new DefaultStatementMappingFactory();
103106
this.mappingResultAdapter = new DefaultResultAdapter();
107+
this.errorStateHandlers = new CopyOnWriteArrayList<>();
104108
this.logger = Logger.getGlobal();
105109

106110
// Default backup value resolvers.
@@ -131,6 +135,16 @@ public void setObjectMapper(@NotNull ObjectMapper objectMapper) {
131135
this.objectMapper = Objects.requireNonNull(objectMapper, "Object mapper cannot be null!");
132136
}
133137

138+
/**
139+
* Adds an error state observer to the list of observers to be
140+
* notified when a fatal error occurs.
141+
*
142+
* @param observer Observer to add.
143+
*/
144+
public void addErrorHandler(@NotNull ErrorStateObserver observer) {
145+
this.errorStateHandlers.add(observer);
146+
}
147+
134148
/**
135149
* Constructs a mapping repository based on provided interface.
136150
* The interface should follow rules for creating mapping repositories
@@ -283,6 +297,7 @@ private QueryRowsResult<Row> doQuery(Query query, boolean isRetry) {
283297
}
284298

285299
logSqlError(e);
300+
notifyError(ErrorCode.QUERY_FATAL);
286301
return new QueryRowsResult<>(false, e.getMessage());
287302
}
288303
}
@@ -315,6 +330,7 @@ private QueryResult doExec(Query query, boolean isRetry) {
315330
}
316331

317332
logSqlError(e);
333+
notifyError(ErrorCode.QUERY_FATAL);
318334
return new QueryResultImpl(false, e.getMessage());
319335
}
320336
}
@@ -441,15 +457,19 @@ public void debug(String message) {
441457
}
442458

443459
@Override
444-
public boolean isLogSqlErrors() {
460+
public final boolean isLogSqlErrors() {
445461
return options.isLogSqlErrors();
446462
}
447463

448464
@Override
449-
public boolean isDebug() {
465+
public final boolean isDebug() {
450466
return options.isDebug();
451467
}
452468

469+
private void notifyError(int code) {
470+
this.errorStateHandlers.forEach(handler -> runCatching(() -> handler.onErrorState(code)));
471+
}
472+
453473
public final SQLDatabaseOptions cloneOptions() {
454474
SQLDatabaseOptions cloned = new SQLDatabaseOptions();
455475
cloned.setDebug(options.isDebug());
@@ -489,4 +509,12 @@ public static class UnknownValueWrapper {
489509
private Object object;
490510
}
491511

512+
public interface ErrorStateObserver {
513+
void onErrorState(int code);
514+
}
515+
516+
public static final class ErrorCode {
517+
public static final int QUERY_FATAL = 0;
518+
}
519+
492520
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package me.zort.sqllib.util;
2+
3+
import lombok.experimental.UtilityClass;
4+
5+
@UtilityClass
6+
public final class ExceptionsUtility {
7+
8+
public static void runCatching(Runnable runnable) {
9+
try {
10+
runnable.run();
11+
} catch (Exception e) {
12+
e.printStackTrace();
13+
}
14+
}
15+
16+
}

0 commit comments

Comments
 (0)