Skip to content

Commit a43d620

Browse files
fix: connection pool test and idle configs (#183)
* fix: connection pool test * fix: version update * fix: tests * fix: backport more changes * fix: backport * Update src/main/java/io/supertokens/storage/postgresql/ConnectionPool.java --------- Co-authored-by: Rishabh Poddar <[email protected]>
1 parent 7f961ab commit a43d620

File tree

9 files changed

+465
-5
lines changed

9 files changed

+465
-5
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
## [Unreleased]
99

10+
## [4.0.3] - 2024-02-07
11+
12+
- Adds tests to check connection pool behaviour.
13+
- Adds `postgresql_idle_connection_timeout` and `postgresql_minimum_idle_connections` configs to control active connections to the database.
14+
1015
## [4.0.2]
1116

1217
- Fixes null pointer issue when user belongs to no tenant.

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ plugins {
22
id 'java-library'
33
}
44

5-
version = "4.0.2"
5+
version = "4.0.3"
66

77
repositories {
88
mavenCentral()

config.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,11 @@ postgresql_config_version: 0
6767
# (DIFFERENT_ACROSS_TENANTS | OPTIONAL | Default: "thirdparty_users") string value. Specify the name of the table
6868
# that will store the thirdparty recipe users.
6969
# postgresql_thirdparty_users_table_name
70+
71+
# (DIFFERENT_ACROSS_TENANTS | OPTIONAL | Default: 60000) long value. Timeout in milliseconds for the idle connections
72+
# to be closed.
73+
# postgresql_idle_connection_timeout:
74+
75+
# (DIFFERENT_ACROSS_TENANTS | OPTIONAL | Default: null) integer value. Minimum number of idle connections to be kept
76+
# active. If not set, minimum idle connections will be same as the connection pool size.
77+
# postgresql_minimum_idle_connections:

devConfig.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,11 @@ postgresql_password: "root"
6969
# (DIFFERENT_ACROSS_TENANTS | OPTIONAL | Default: "thirdparty_users") string value. Specify the name of the table
7070
# that will store the thirdparty recipe users.
7171
# postgresql_thirdparty_users_table_name
72+
73+
# (DIFFERENT_ACROSS_TENANTS | OPTIONAL | Default: 60000) long value. Timeout in milliseconds for the idle connections
74+
# to be closed.
75+
# postgresql_idle_connection_timeout:
76+
77+
# (DIFFERENT_ACROSS_TENANTS | OPTIONAL | Default: null) integer value. Minimum number of idle connections to be kept
78+
# active. If not set, minimum idle connections will be same as the connection pool size.
79+
# postgresql_minimum_idle_connections:

src/main/java/io/supertokens/storage/postgresql/ConnectionPool.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ private synchronized void initialiseHikariDataSource() throws SQLException {
8181
}
8282
config.setMaximumPoolSize(userConfig.getConnectionPoolSize());
8383
config.setConnectionTimeout(5000);
84+
if (userConfig.getMinimumIdleConnections() != null) {
85+
config.setMinimumIdle(userConfig.getMinimumIdleConnections());
86+
config.setIdleTimeout(userConfig.getIdleConnectionTimeout());
87+
}
8488
config.addDataSourceProperty("cachePrepStmts", "true");
8589
config.addDataSourceProperty("prepStmtCacheSize", "250");
8690
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");

src/main/java/io/supertokens/storage/postgresql/Start.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@
100100
import java.sql.SQLTransactionRollbackException;
101101
import java.util.*;
102102

103+
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.execute;
104+
103105
public class Start
104106
implements SessionSQLStorage, EmailPasswordSQLStorage, EmailVerificationSQLStorage, ThirdPartySQLStorage,
105107
JWTRecipeSQLStorage, PasswordlessSQLStorage, UserMetadataSQLStorage, UserRolesSQLStorage, UserIdMappingStorage,
@@ -109,7 +111,8 @@ public class Start
109111
// SaaS. If the core is not running in SuperTokens SaaS, this array has no effect.
110112
private static String[] PROTECTED_DB_CONFIG = new String[]{"postgresql_connection_pool_size",
111113
"postgresql_connection_uri", "postgresql_host", "postgresql_port", "postgresql_user", "postgresql_password",
112-
"postgresql_database_name", "postgresql_table_schema"};
114+
"postgresql_database_name", "postgresql_table_schema", "postgresql_idle_connection_timeout",
115+
"postgresql_minimum_idle_connections"};
113116
private static final Object appenderLock = new Object();
114117
public static boolean silent = false;
115118
private ResourceDistributor resourceDistributor = new ResourceDistributor();
@@ -2819,4 +2822,17 @@ public String[] getAllTablesInTheDatabaseThatHasDataForAppId(String appId) throw
28192822
public Thread getMainThread() {
28202823
return mainThread;
28212824
}
2825+
2826+
@TestOnly
2827+
public int getDbActivityCount(String dbname) throws SQLException, StorageQueryException {
2828+
String QUERY = "SELECT COUNT(*) as c FROM pg_stat_activity WHERE datname = ?;";
2829+
return execute(this, QUERY, pst -> {
2830+
pst.setString(1, dbname);
2831+
}, result -> {
2832+
if (result.next()) {
2833+
return result.getInt("c");
2834+
}
2835+
return -1;
2836+
});
2837+
}
28222838
}

src/main/java/io/supertokens/storage/postgresql/config/PostgreSQLConfig.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,14 @@ public class PostgreSQLConfig {
112112
@ConnectionPoolProperty
113113
private String postgresql_connection_scheme = "postgresql";
114114

115+
@JsonProperty
116+
@ConnectionPoolProperty
117+
private long postgresql_idle_connection_timeout = 60000;
118+
119+
@JsonProperty
120+
@ConnectionPoolProperty
121+
private Integer postgresql_minimum_idle_connections = null;
122+
115123
@IgnoreForAnnotationCheck
116124
boolean isValidAndNormalised = false;
117125

@@ -234,6 +242,14 @@ public String getThirdPartyUsersTable() {
234242
return postgresql_thirdparty_users_table_name;
235243
}
236244

245+
public long getIdleConnectionTimeout() {
246+
return postgresql_idle_connection_timeout;
247+
}
248+
249+
public Integer getMinimumIdleConnections() {
250+
return postgresql_minimum_idle_connections;
251+
}
252+
237253
public String getThirdPartyUserToTenantTable() {
238254
return addSchemaAndPrefixToTableName("thirdparty_user_to_tenant");
239255
}
@@ -340,6 +356,20 @@ public void validateAndNormalise() throws InvalidConfigException {
340356
"'postgresql_connection_pool_size' in the config.yaml file must be > 0");
341357
}
342358

359+
if (postgresql_minimum_idle_connections != null) {
360+
if (postgresql_minimum_idle_connections < 0) {
361+
throw new InvalidConfigException(
362+
"'postgresql_minimum_idle_connections' must be >= 0");
363+
}
364+
365+
if (postgresql_minimum_idle_connections > postgresql_connection_pool_size) {
366+
throw new InvalidConfigException(
367+
"'postgresql_minimum_idle_connections' must be less than or equal to "
368+
+ "'postgresql_connection_pool_size'");
369+
}
370+
}
371+
372+
343373
// Normalisation
344374
if (postgresql_connection_uri != null) {
345375
{ // postgresql_connection_attributes

0 commit comments

Comments
 (0)