diff --git a/app/build.gradle b/app/build.gradle index 9b91f56..d3e0d46 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -35,7 +35,6 @@ dependencies { implementation "com.google.protobuf:protobuf-java:$protobufVersion" implementation('org.glassfish.jersey.containers:jersey-container-servlet:3.1.0') - implementation('org.glassfish.jersey.inject:jersey-hk2:3.1.0') //jOOQ & Postgres impl deps implementation "org.jooq:jooq:$jooqVersion" @@ -43,16 +42,15 @@ dependencies { implementation "org.jooq:jooq-codegen:$jooqVersion" runtimeOnly "org.postgresql:postgresql:$postgresVersion" jooqGenerator "org.postgresql:postgresql:$postgresVersion" + implementation 'com.zaxxer:HikariCP:5.0.1' // Connection pooling for postgres/jdbc implementation "com.google.inject:guice:$guiceVersion" + implementation('org.glassfish.jersey.inject:jersey-hk2:3.1.0') implementation "org.glassfish.hk2:guice-bridge:3.0.3" compileOnly 'org.projectlombok:lombok:1.18.24' annotationProcessor 'org.projectlombok:lombok:1.18.24' - compileOnly 'org.projectlombok:lombok:1.18.24' - annotationProcessor 'org.projectlombok:lombok:1.18.24' - testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" testImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion" testImplementation "org.mockito:mockito-core:$mockitoVersion" diff --git a/app/src/main/java/org/vss/guice/BaseModule.java b/app/src/main/java/org/vss/guice/BaseModule.java index 19b9204..a33ccac 100644 --- a/app/src/main/java/org/vss/guice/BaseModule.java +++ b/app/src/main/java/org/vss/guice/BaseModule.java @@ -1,13 +1,83 @@ package org.vss.guice; import com.google.inject.AbstractModule; +import com.google.inject.Provides; import com.google.inject.Singleton; +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; +import org.jooq.DSLContext; +import org.jooq.SQLDialect; +import org.jooq.impl.DSL; import org.vss.KVStore; import org.vss.impl.postgres.PostgresBackendImpl; public class BaseModule extends AbstractModule { + @Override protected void configure() { + // Provide PostgresBackend as default implementation for KVStore. bind(KVStore.class).to(PostgresBackendImpl.class).in(Singleton.class); } + + @Provides + @Singleton + // Provide DSLContext which is to be used by PostgresBackend + public DSLContext provideDSLContext() throws ClassNotFoundException { + // Required to load postgres drivers in tomcat + Class.forName("org.postgresql.Driver"); + return DSL.using(HikariCPDataSource.dataSource, SQLDialect.POSTGRES); + } +} + +// Provide Hikari Connection Pooling configuration for jdbc connection management. +// Hikari is high-performance connection pooling library which will maintain a set of connections +// to the database for us. +// When we provide `HikariCPDataSource` to DSLContext, jOOQ will internally `acquire` and `release` +// connections from pool. +// For HikariCP config, we provide some sane defaults, but they are meant to be changed and tuned. +// For specific parameter functionality, refer to HikariCP docs. +class HikariCPDataSource { + + private static HikariConfig config = new HikariConfig(); + public static HikariDataSource dataSource; + + static { + try (InputStream input = HikariCPDataSource.class.getClassLoader() + .getResourceAsStream("hikariJdbc.properties")) { + Properties hikariJdbcProperties = new Properties(); + hikariJdbcProperties.load(input); + + config.setJdbcUrl(hikariJdbcProperties.getProperty("jdbc.url")); + config.setUsername(hikariJdbcProperties.getProperty("jdbc.username")); + config.setPassword(hikariJdbcProperties.getProperty("jdbc.password")); + + config.setMaximumPoolSize( + Integer.parseInt(hikariJdbcProperties.getProperty("hikaricp.maxPoolSize"))); + config.setMinimumIdle( + Integer.parseInt(hikariJdbcProperties.getProperty("hikaricp.minimumIdle"))); + config.setConnectionTimeout( + Long.parseLong(hikariJdbcProperties.getProperty("hikaricp.connectionTimeout"))); + config.setIdleTimeout( + Long.parseLong(hikariJdbcProperties.getProperty("hikaricp.idleTimeout"))); + config.setMaxLifetime( + Long.parseLong(hikariJdbcProperties.getProperty("hikaricp.maxLifetime"))); + + config.addDataSourceProperty("cachePrepStmts", + hikariJdbcProperties.getProperty("hikaricp.cachePrepStmts")); + config.addDataSourceProperty("prepStmtCacheSize", + hikariJdbcProperties.getProperty("hikaricp.prepStmtCacheSize")); + config.addDataSourceProperty("prepStmtCacheSqlLimit", + hikariJdbcProperties.getProperty("hikaricp.prepStmtCacheSqlLimit")); + + dataSource = new HikariDataSource(config); + } catch (IOException e) { + throw new RuntimeException("Unable to read hikariJdbcProperties from resources"); + } + } + + private HikariCPDataSource() { + } } diff --git a/app/src/main/resources/hikariJdbc.properties b/app/src/main/resources/hikariJdbc.properties new file mode 100644 index 0000000..fd8dcfb --- /dev/null +++ b/app/src/main/resources/hikariJdbc.properties @@ -0,0 +1,23 @@ +# Default properties, these are meant to be changed according to application needs. + +jdbc.url=jdbc:postgresql://localhost:5432/postgres +jdbc.username=postgres +jdbc.password= + +# Idle Timeout +hikaricp.minimumIdle=10 + +# Set connectionTimeout to 30 secs +hikaricp.connectionTimeout=30000 + +# Set idle timeout to 10 minutes +hikaricp.idleTimeout=600000 + +# Set Maximum lifetime of a connection to 30minutes +hikaricp.maxLifetime=1800000 + +# Performance Optimizations +hikaricp.maxPoolSize=50 +hikaricp.cachePrepStmts=true +hikaricp.prepStmtCacheSize=250 +hikaricp.prepStmtCacheSqlLimit=2048