Skip to content

Commit

Permalink
Increased logs to debug future connection leaks. (#2437)
Browse files Browse the repository at this point in the history
* Increased logs to debug future connection leaks.

* Fetch a connection from the pool only if a query exists.

* Minor comment added.

* Minor rewrite

* Code formatting.

* Update app/server/appsmith-plugins/postgresPlugin/src/main/java/com/external/plugins/PostgresPlugin.java

Co-authored-by: Shrikant Sharat Kandula <[email protected]>

* Added hikari cp pool stats to get database structure function as well.

Co-authored-by: Shrikant Sharat Kandula <[email protected]>
  • Loading branch information
trishaanand and sharat87 committed Jan 5, 2021
1 parent 45918bf commit db2b002
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.appsmith.external.plugins.PluginExecutor;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import com.zaxxer.hikari.HikariPoolMXBean;
import org.apache.commons.lang.ObjectUtils;
import org.pf4j.Extension;
import org.pf4j.PluginWrapper;
Expand Down Expand Up @@ -52,7 +53,7 @@ public class PostgresPlugin extends BasePlugin {

private static final int MINIMUM_POOL_SIZE = 1;

private static final int MAXIMUM_POOL_SIZE = 20;
private static final int MAXIMUM_POOL_SIZE = 5;

private static final long LEAK_DETECTION_TIME_MS = 60*1000;

Expand Down Expand Up @@ -114,27 +115,41 @@ public Mono<ActionExecutionResult> execute(HikariDataSource connection,

return Mono.fromCallable(() -> {

Connection connectionFromPool;

try {
connectionFromPool = getConnectionFromConnectionPool(connection, datasourceConfiguration);
} catch (StaleConnectionException e) {
return Mono.error(e);
} catch (SQLException e) {
return Mono.error(new AppsmithPluginException(AppsmithPluginError.PLUGIN_ERROR, e.getMessage()));
}

String query = actionConfiguration.getBody();
// Check for query parameter before performing the probably expensive fetch connection from the pool op.
if (query == null) {
return Mono.error(new AppsmithPluginException(AppsmithPluginError.PLUGIN_ERROR, "Missing required parameter: Query."));
}

Connection connectionFromPool = null;

try {
connectionFromPool = getConnectionFromConnectionPool(connection, datasourceConfiguration);
} catch (SQLException | StaleConnectionException e) {
// The function can throw either StaleConnectionException or SQLException. The underlying hikari
// library throws SQLException in case the pool is closed or there is an issue initializing
// the connection pool which can also be translated in our world to StaleConnectionException
// and should then trigger the destruction and recreation of the pool.
return Mono.error(e instanceof StaleConnectionException ? e : new StaleConnectionException());
}

List<Map<String, Object>> rowsList = new ArrayList<>(50);

Statement statement = null;
ResultSet resultSet = null;
System.out.println(Thread.currentThread().getName() +
": Going to execute query" + query);

HikariPoolMXBean poolProxy = connection.getHikariPoolMXBean();

int idleConnections = poolProxy.getIdleConnections();
int activeConnections = poolProxy.getActiveConnections();
int totalConnections = poolProxy.getTotalConnections();
int threadsAwaitingConnection = poolProxy.getThreadsAwaitingConnection();
System.out.println(Thread.currentThread().getName() + ": Before executing postgres query [" +
query +
"] Hikari Pool stats : active - " + activeConnections +
", idle - " + idleConnections +
", awaiting - " + threadsAwaitingConnection +
", total - " + totalConnections );
try {
statement = connectionFromPool.createStatement();
boolean isResultSet = statement.execute(query);
Expand Down Expand Up @@ -197,8 +212,17 @@ public Mono<ActionExecutionResult> execute(HikariDataSource connection,
}

} catch (SQLException e) {
System.out.println(Thread.currentThread().getName() + ": In the PostgresPlugin, got action execution error");
return Mono.error(new AppsmithPluginException(AppsmithPluginError.PLUGIN_ERROR, e.getMessage()));
} finally {
idleConnections = poolProxy.getIdleConnections();
activeConnections = poolProxy.getActiveConnections();
totalConnections = poolProxy.getTotalConnections();
threadsAwaitingConnection = poolProxy.getThreadsAwaitingConnection();
System.out.println(Thread.currentThread().getName() + ": After executing postgres query, Hikari Pool stats active - " + activeConnections +
", idle - " + idleConnections +
", awaiting - " + threadsAwaitingConnection +
", total - " + totalConnections );
if (resultSet != null) {
try {
resultSet.close();
Expand Down Expand Up @@ -334,12 +358,26 @@ public Mono<DatasourceStructure> getStructure(HikariDataSource connection, Datas
Connection connectionFromPool;
try {
connectionFromPool = getConnectionFromConnectionPool(connection, datasourceConfiguration);
} catch (StaleConnectionException e) {
return Mono.error(e);
} catch (SQLException e) {
return Mono.error(new AppsmithPluginException(AppsmithPluginError.PLUGIN_ERROR, e.getMessage()));
} catch (SQLException | StaleConnectionException e) {
// The function can throw either StaleConnectionException or SQLException. The underlying hikari
// library throws SQLException in case the pool is closed or there is an issue initializing
// the connection pool which can also be translated in our world to StaleConnectionException
// and should then trigger the destruction and recreation of the pool.
return Mono.error(e instanceof StaleConnectionException ? e : new StaleConnectionException());
}

HikariPoolMXBean poolProxy = connection.getHikariPoolMXBean();

int idleConnections = poolProxy.getIdleConnections();
int activeConnections = poolProxy.getActiveConnections();
int totalConnections = poolProxy.getTotalConnections();
int threadsAwaitingConnection = poolProxy.getThreadsAwaitingConnection();
System.out.println(Thread.currentThread().getName() + ": Before getting postgres db structure" +
" Hikari Pool stats : active - " + activeConnections +
", idle - " + idleConnections +
", awaiting - " + threadsAwaitingConnection +
", total - " + totalConnections );

// Ref: <https://docs.oracle.com/en/java/javase/11/docs/api/java.sql/java/sql/DatabaseMetaData.html>.
try (Statement statement = connectionFromPool.createStatement()) {

Expand Down Expand Up @@ -467,6 +505,14 @@ public Mono<DatasourceStructure> getStructure(HikariDataSource connection, Datas
} catch (SQLException throwable) {
return Mono.error(throwable);
} finally {
idleConnections = poolProxy.getIdleConnections();
activeConnections = poolProxy.getActiveConnections();
totalConnections = poolProxy.getTotalConnections();
threadsAwaitingConnection = poolProxy.getThreadsAwaitingConnection();
System.out.println(Thread.currentThread().getName() + ": After postgres db structure, Hikari Pool stats active - " + activeConnections +
", idle - " + idleConnections +
", awaiting - " + threadsAwaitingConnection +
", total - " + totalConnections );

if (connectionFromPool != null) {
try {
Expand Down Expand Up @@ -496,8 +542,7 @@ public Mono<DatasourceStructure> getStructure(HikariDataSource connection, Datas
* @param datasourceConfiguration
* @return connection pool
*/
private static HikariDataSource createConnectionPool(DatasourceConfiguration datasourceConfiguration)
{
private static HikariDataSource createConnectionPool(DatasourceConfiguration datasourceConfiguration) {
HikariConfig config = new HikariConfig();

config.setDriverClassName(JDBC_DRIVER);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,8 @@ public Mono<ActionExecutionResult> executeAction(ExecuteActionDTO executeActionD
)
)
.onErrorResume(e -> {
log.debug("In the action execution error mode.", e);
log.debug("{}: In the action execution error mode.",
Thread.currentThread().getName(), e);
ActionExecutionResult result = new ActionExecutionResult();
result.setBody(e.getMessage());
result.setIsExecutionSuccess(false);
Expand Down

0 comments on commit db2b002

Please sign in to comment.