diff --git a/backend/openshift.deploy.yml b/backend/openshift.deploy.yml
index a37cb5ba..371b43ff 100644
--- a/backend/openshift.deploy.yml
+++ b/backend/openshift.deploy.yml
@@ -40,13 +40,13 @@ parameters:
value: "90000"
- name: DB_POOL_IDLE_TIMEOUT
description: Maximum amount of milliseconds that a connection is allowed to sit idle in the pool.
- value: "0"
+ value: "60000"
- name: DB_POOL_MAX_LIFETIME
description: Maximum lifetime of a connection in the pool.
- value: "1800000"
+ value: "120000"
- name: DB_POOL_MAX_SIZE
description: Maximum number of connections per pod
- value: "3"
+ value: "1"
- name: DB_POOL_MIN_IDLE
description: Minimum number of connections per pod
value: "1"
diff --git a/backend/pom.xml b/backend/pom.xml
index d292a5f7..e8c50967 100644
--- a/backend/pom.xml
+++ b/backend/pom.xml
@@ -129,12 +129,6 @@
1.18.30
true
-
- org.springframework.boot
- spring-boot-devtools
- runtime
- true
-
diff --git a/backend/src/main/java/ca/bc/gov/restapi/results/oracle/config/OracleGracefulShutdownConfig.java b/backend/src/main/java/ca/bc/gov/restapi/results/oracle/config/OracleGracefulShutdownConfig.java
new file mode 100644
index 00000000..06bf84de
--- /dev/null
+++ b/backend/src/main/java/ca/bc/gov/restapi/results/oracle/config/OracleGracefulShutdownConfig.java
@@ -0,0 +1,20 @@
+package ca.bc.gov.restapi.results.oracle.config;
+
+import jakarta.persistence.EntityManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextClosedEvent;
+import org.springframework.lang.NonNull;
+import org.springframework.stereotype.Component;
+
+/** This class adds a listener for closing connection gracefully. */
+@Component
+public class OracleGracefulShutdownConfig implements ApplicationListener {
+
+ @Autowired private EntityManager oracleEntityManager;
+
+ @Override
+ public void onApplicationEvent(@NonNull ContextClosedEvent event) {
+ oracleEntityManager.close();
+ }
+}
diff --git a/backend/src/main/java/ca/bc/gov/restapi/results/oracle/config/OracleHikariConfig.java b/backend/src/main/java/ca/bc/gov/restapi/results/oracle/config/OracleHikariConfig.java
new file mode 100644
index 00000000..bea36c55
--- /dev/null
+++ b/backend/src/main/java/ca/bc/gov/restapi/results/oracle/config/OracleHikariConfig.java
@@ -0,0 +1,27 @@
+package ca.bc.gov.restapi.results.oracle.config;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/** This class holds configurations for the Oracle Hikari connection pool. */
+@Getter
+@Setter
+@Configuration
+@ConfigurationProperties("spring.datasource.oracle")
+public class OracleHikariConfig {
+
+ private String driverClassName;
+ private String url;
+ private String username;
+ private String password;
+ private long connectionTimeout;
+ private long idleTimeout;
+ private long maxLifetime;
+ private long keepaliveTime;
+ private String poolName;
+ private int minimumIdle;
+ private int maximumPoolSize;
+ private long leakDetectionThreshold;
+}
diff --git a/backend/src/main/java/ca/bc/gov/restapi/results/oracle/config/OraclePersistenceConfig.java b/backend/src/main/java/ca/bc/gov/restapi/results/oracle/config/OraclePersistenceConfig.java
index 65e9b848..39861e31 100644
--- a/backend/src/main/java/ca/bc/gov/restapi/results/oracle/config/OraclePersistenceConfig.java
+++ b/backend/src/main/java/ca/bc/gov/restapi/results/oracle/config/OraclePersistenceConfig.java
@@ -1,6 +1,9 @@
package ca.bc.gov.restapi.results.oracle.config;
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -11,15 +14,32 @@
@Configuration
public class OraclePersistenceConfig {
+ @Autowired private OracleHikariConfig oracleHikariConfig;
+
@Bean
@ConfigurationProperties("spring.datasource.oracle")
public DataSourceProperties oracleDataSourceProperties() {
return new DataSourceProperties();
}
+ /** Creates a Postgres Datasource with all Hikari connection pool configuration. */
@Bean
@Primary
public DataSource oracleDataSource() {
- return oracleDataSourceProperties().initializeDataSourceBuilder().build();
+ HikariConfig config = new HikariConfig();
+ config.setJdbcUrl(oracleHikariConfig.getUrl());
+ config.setUsername(oracleHikariConfig.getUsername());
+ config.setPassword(oracleHikariConfig.getPassword());
+ config.setDriverClassName(oracleHikariConfig.getDriverClassName());
+ config.setConnectionTimeout(oracleHikariConfig.getConnectionTimeout());
+ config.setIdleTimeout(oracleHikariConfig.getIdleTimeout());
+ config.setMaxLifetime(oracleHikariConfig.getMaxLifetime());
+ config.setKeepaliveTime(oracleHikariConfig.getKeepaliveTime());
+ config.setPoolName(oracleHikariConfig.getPoolName());
+ config.setMinimumIdle(oracleHikariConfig.getMinimumIdle());
+ config.setMaximumPoolSize(oracleHikariConfig.getMaximumPoolSize());
+ config.setLeakDetectionThreshold(oracleHikariConfig.getLeakDetectionThreshold());
+
+ return new HikariDataSource(config);
}
}
diff --git a/backend/src/main/java/ca/bc/gov/restapi/results/postgres/config/PostgresGracefulShutdownConfig.java b/backend/src/main/java/ca/bc/gov/restapi/results/postgres/config/PostgresGracefulShutdownConfig.java
new file mode 100644
index 00000000..f1f7e029
--- /dev/null
+++ b/backend/src/main/java/ca/bc/gov/restapi/results/postgres/config/PostgresGracefulShutdownConfig.java
@@ -0,0 +1,20 @@
+package ca.bc.gov.restapi.results.postgres.config;
+
+import jakarta.persistence.EntityManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextClosedEvent;
+import org.springframework.lang.NonNull;
+import org.springframework.stereotype.Component;
+
+/** This class adds a listener for closing connection gracefully. */
+@Component
+public class PostgresGracefulShutdownConfig implements ApplicationListener {
+
+ @Autowired private EntityManager postgresEntityManager;
+
+ @Override
+ public void onApplicationEvent(@NonNull ContextClosedEvent event) {
+ postgresEntityManager.close();
+ }
+}
diff --git a/backend/src/main/java/ca/bc/gov/restapi/results/postgres/config/PostgresHikariConfig.java b/backend/src/main/java/ca/bc/gov/restapi/results/postgres/config/PostgresHikariConfig.java
new file mode 100644
index 00000000..934ac253
--- /dev/null
+++ b/backend/src/main/java/ca/bc/gov/restapi/results/postgres/config/PostgresHikariConfig.java
@@ -0,0 +1,27 @@
+package ca.bc.gov.restapi.results.postgres.config;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/** This class holds configurations for the Postgres Hikari connection pool. */
+@Getter
+@Setter
+@Configuration
+@ConfigurationProperties("spring.datasource.postgres")
+public class PostgresHikariConfig {
+
+ private String driverClassName;
+ private String url;
+ private String username;
+ private String password;
+ private long connectionTimeout;
+ private long idleTimeout;
+ private long maxLifetime;
+ private long keepaliveTime;
+ private String poolName;
+ private int minimumIdle;
+ private int maximumPoolSize;
+ private long leakDetectionThreshold;
+}
diff --git a/backend/src/main/java/ca/bc/gov/restapi/results/postgres/config/PostgresJpaConfig.java b/backend/src/main/java/ca/bc/gov/restapi/results/postgres/config/PostgresJpaConfig.java
index 97ed2300..1065f5fd 100644
--- a/backend/src/main/java/ca/bc/gov/restapi/results/postgres/config/PostgresJpaConfig.java
+++ b/backend/src/main/java/ca/bc/gov/restapi/results/postgres/config/PostgresJpaConfig.java
@@ -45,10 +45,14 @@ public class PostgresJpaConfig {
@Bean
public LocalContainerEntityManagerFactoryBean postgresEntityManagerFactory(
@Qualifier("postgresDataSource") DataSource dataSource, EntityManagerFactoryBuilder builder) {
- LocalContainerEntityManagerFactoryBean build =
- builder.dataSource(dataSource).packages(getPostgresEntities()).build();
Properties jpaProps = new Properties();
jpaProps.setProperty("hibernate.default_schema", "silva");
+ jpaProps.setProperty("hibernate.ddl-auto", "update");
+ jpaProps.setProperty("defer-datasource-initialization", "true");
+ jpaProps.setProperty("sql.init.mode", "always");
+
+ LocalContainerEntityManagerFactoryBean build =
+ builder.dataSource(dataSource).packages(getPostgresEntities()).build();
build.setJpaProperties(jpaProps);
return build;
}
diff --git a/backend/src/main/java/ca/bc/gov/restapi/results/postgres/config/PostgresPersistenceConfig.java b/backend/src/main/java/ca/bc/gov/restapi/results/postgres/config/PostgresPersistenceConfig.java
index ab855190..bdfcf5d9 100644
--- a/backend/src/main/java/ca/bc/gov/restapi/results/postgres/config/PostgresPersistenceConfig.java
+++ b/backend/src/main/java/ca/bc/gov/restapi/results/postgres/config/PostgresPersistenceConfig.java
@@ -1,6 +1,9 @@
package ca.bc.gov.restapi.results.postgres.config;
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -10,14 +13,31 @@
@Configuration
public class PostgresPersistenceConfig {
+ @Autowired private PostgresHikariConfig postgresHikariConfig;
+
@Bean
@ConfigurationProperties("spring.datasource.postgres")
public DataSourceProperties postgresDataSourceProperties() {
return new DataSourceProperties();
}
+ /** Creates a Postgres Datasource with all Hikari connection pool configuration. */
@Bean
public DataSource postgresDataSource() {
- return postgresDataSourceProperties().initializeDataSourceBuilder().build();
+ HikariConfig config = new HikariConfig();
+ config.setJdbcUrl(postgresHikariConfig.getUrl());
+ config.setUsername(postgresHikariConfig.getUsername());
+ config.setPassword(postgresHikariConfig.getPassword());
+ config.setDriverClassName(postgresHikariConfig.getDriverClassName());
+ config.setConnectionTimeout(postgresHikariConfig.getConnectionTimeout());
+ config.setIdleTimeout(postgresHikariConfig.getIdleTimeout());
+ config.setMaxLifetime(postgresHikariConfig.getMaxLifetime());
+ config.setKeepaliveTime(postgresHikariConfig.getKeepaliveTime());
+ config.setPoolName(postgresHikariConfig.getPoolName());
+ config.setMinimumIdle(postgresHikariConfig.getMinimumIdle());
+ config.setMaximumPoolSize(postgresHikariConfig.getMaximumPoolSize());
+ config.setLeakDetectionThreshold(postgresHikariConfig.getLeakDetectionThreshold());
+
+ return new HikariDataSource(config);
}
}
diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties
index 1b0e5f75..89945b6e 100644
--- a/backend/src/main/resources/application.properties
+++ b/backend/src/main/resources/application.properties
@@ -3,6 +3,7 @@ logging.level.ca.bc.gov.restapi.results = ${LOGGING_LEVEL:INFO}
spring.application.name = results-api
server.error.include-message=always
server.port = ${SERVER_PORT:8080}
+server.shutdown = graceful
# Actuator and ops
management.endpoint.health.show-details = always
@@ -23,31 +24,28 @@ spring.datasource.oracle.driver-class-name = oracle.jdbc.OracleDriver
spring.datasource.oracle.url = jdbc:oracle:thin:@tcps://${DATABASE_HOST:nrcdb03.bcgov}:${DATABASE_PORT:1543}/${SERVICE_NAME:dbq01.nrs.bcgov}?javax.net.ssl.trustStore=${ca.bc.gov.nrs.oracle.keystore}&javax.net.ssl.trustStorePassword=${ca.bc.gov.nrs.oracle.secret}&javax.net.ssl.keyStore=${ca.bc.gov.nrs.oracle.keystore}&javax.net.ssl.keyStorePassword=${ca.bc.gov.nrs.oracle.secret}&oracle.net.ssl_certificate_alias=${ca.bc.gov.nrs.oracle.host}&oracle.net.ssl_server_dn_match=false
spring.datasource.oracle.username = ${DATABASE_USER}
spring.datasource.oracle.password = ${DATABASE_PASSWORD}
-spring.datasource.oracle.hikari.connectionTimeout = ${DB_POOL_CONN_TIMEOUT:90000}
-spring.datasource.oracle.hikari.idleTimeout = ${DB_POOL_IDLE_TIMEOUT:45000}
-spring.datasource.oracle.hikari.maxLifetime = ${DB_POOL_MAX_LIFETIME:30000}
-spring.datasource.oracle.hikari.keepaliveTime = 30000
-spring.datasource.oracle.hikari.poolName = SilvaOracleConnPool
-spring.datasource.oracle.hikari.minimumIdle = ${DB_POOL_MIN_IDLE:1}
-spring.datasource.oracle.hikari.maximumPoolSize = ${DB_POOL_MAX_SIZE:3}
-#spring.jpa.database-platform = org.hibernate.dialect.OracleDialect
+spring.datasource.oracle.connectionTimeout = ${DB_POOL_CONN_TIMEOUT:90000}
+spring.datasource.oracle.idleTimeout = ${DB_POOL_IDLE_TIMEOUT:60000}
+spring.datasource.oracle.maxLifetime = ${DB_POOL_MAX_LIFETIME:120000}
+spring.datasource.oracle.keepaliveTime = 30000
+spring.datasource.oracle.poolName = SilvaOracleConnPool
+spring.datasource.oracle.minimumIdle = ${DB_POOL_MIN_IDLE:1}
+spring.datasource.oracle.maximumPoolSize = ${DB_POOL_MAX_SIZE:1}
+spring.datasource.oracle.leakDetectionThreshold = 20000
# Database, and JPA - Postgres
spring.datasource.postgres.driver-class-name = org.postgresql.Driver
spring.datasource.postgres.url = jdbc:postgresql://${POSTGRES_HOST:localhost}:5432/${POSTGRES_DB:postgres}
spring.datasource.postgres.username = ${POSTGRES_USER:postgres}
spring.datasource.postgres.password = ${POSTGRES_PASSWORD:default}
-spring.datasource.postgres.hikari.connectionTimeout = ${DB_POOL_CONN_TIMEOUT:90000}
-spring.datasource.postgres.hikari.idleTimeout = ${DB_POOL_IDLE_TIMEOUT:45000}
-spring.datasource.postgres.hikari.maxLifetime = ${DB_POOL_MAX_LIFETIME:30000}
-spring.datasource.postgres.hikari.keepaliveTime = 30000
-spring.datasource.postgres.hikari.poolName = SilvaPostgresConnPool
-spring.datasource.postgres.hikari.minimumIdle = ${DB_POOL_MIN_IDLE:1}
-spring.datasource.postgres.hikari.maximumPoolSize = ${DB_POOL_MAX_SIZE:3}
-#spring.jpa.database-platform = org.hibernate.dialect.PostgreSQLDialect
-#spring.jpa.hibernate.ddl-auto = update
-#spring.jpa.defer-datasource-initialization=true
-#spring.sql.init.mode=always
+spring.datasource.postgres.connectionTimeout = ${DB_POOL_CONN_TIMEOUT:90000}
+spring.datasource.postgres.idleTimeout = ${DB_POOL_IDLE_TIMEOUT:60000}
+spring.datasource.postgres.maxLifetime = ${DB_POOL_MAX_LIFETIME:120000}
+spring.datasource.postgres.keepaliveTime = 30000
+spring.datasource.postgres.poolName = SilvaPostgresConnPool
+spring.datasource.postgres.minimumIdle = ${DB_POOL_MIN_IDLE:1}
+spring.datasource.postgres.maximumPoolSize = ${DB_POOL_MAX_SIZE:1}
+spring.datasource.postgres.leakDetectionThreshold = 20000
# Common database settings
spring.jpa.show-sql = true