diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java index 331707c38..280cead71 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java @@ -70,6 +70,15 @@ public class PostgreSQLAuthenticationProviderModule implements Module { myBatisProperties.setProperty("mybatis.pooled.pingEnabled", "true"); myBatisProperties.setProperty("mybatis.pooled.pingQuery", "SELECT 1"); + // Only set if > 0. Underlying backend does not take 0 as not-set. + int defaultStatementTimeout = environment.getPostgreSQLDefaultStatementTimeout(); + if (defaultStatementTimeout > 0) { + myBatisProperties.setProperty( + "mybatis.configuration.defaultStatementTimeout", + String.valueOf(defaultStatementTimeout) + ); + } + // Use UTF-8 in database driverProperties.setProperty("characterEncoding", "UTF-8"); @@ -110,6 +119,12 @@ public class PostgreSQLAuthenticationProviderModule implements Module { } + // Handle case where TCP connection to database is silently dropped + driverProperties.setProperty( + "socketTimeout", + String.valueOf(environment.getPostgreSQLSocketTimeout()) + ); + } @Override diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLEnvironment.java index e81e6949e..012877cf6 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLEnvironment.java @@ -48,6 +48,19 @@ public class PostgreSQLEnvironment extends JDBCEnvironment { */ private static final int DEFAULT_PORT = 5432; + /** + * The default number of seconds the driver will wait for a response from + * the database, before aborting the query. + * A value of 0 (the default) means the timeout is disabled. + */ + private static final int DEFAULT_STATEMENT_TIMEOUT = 0; + + /** + * The default number of seconds to wait for socket read operations. + * A value of 0 (the default) means the timeout is disabled. + */ + private static final int DEFAULT_SOCKET_TIMEOUT = 0; + /** * Whether a database user account is required by default for authentication * to succeed. @@ -249,6 +262,41 @@ public class PostgreSQLEnvironment extends JDBCEnvironment { public String getPostgreSQLPassword() throws GuacamoleException { return getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_PASSWORD); } + + /** + * Returns the defaultStatementTimeout set for PostgreSQL connections. + * If unspecified, this will default to 0, + * and should not be passed through to the backend. + * + * @return + * The statement timeout (in seconds) + * + * @throws GuacamoleException + * If an error occurs while retrieving the property value. + */ + public int getPostgreSQLDefaultStatementTimeout() throws GuacamoleException { + return getProperty( + PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_STATEMENT_TIMEOUT, + DEFAULT_STATEMENT_TIMEOUT + ); + } + + /** + * Returns the socketTimeout property to set on PostgreSQL connections. + * If unspecified, this will default to 0 (no timeout) + * + * @return + * The socketTimeout to use when waiting on read operations (in seconds) + * + * @throws GuacamoleException + * If an error occurs while retrieving the property value. + */ + public int getPostgreSQLSocketTimeout() throws GuacamoleException { + return getProperty( + PostgreSQLGuacamoleProperties.POSTGRESQL_SOCKET_TIMEOUT, + DEFAULT_SOCKET_TIMEOUT + ); + } @Override public boolean isRecursiveQuerySupported(SqlSession session) { diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLGuacamoleProperties.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLGuacamoleProperties.java index d2ae2532c..271d9c0dd 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLGuacamoleProperties.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLGuacamoleProperties.java @@ -94,6 +94,36 @@ public class PostgreSQLGuacamoleProperties { }; + /** + * The number of seconds the driver will wait for a response from + * the database, before aborting the query. + * A value of 0 (the default) means the timeout is disabled. + */ + public static final IntegerGuacamoleProperty + POSTGRESQL_DEFAULT_STATEMENT_TIMEOUT = new IntegerGuacamoleProperty() { + + @Override + public String getName() { return "postgresql-default-statement-timeout"; } + + }; + + /** + * The number of seconds to wait for socket read operations. + * If reading from the server takes longer than this value, the + * connection will be closed. This can be used to handle network problems + * such as a dropped connection to the database. Similar to + * postgresql-default-statement-timeout, it will have the effect of + * aborting queries that take too long. + * A value of 0 (the default) means the timeout is disabled. + */ + public static final IntegerGuacamoleProperty + POSTGRESQL_SOCKET_TIMEOUT = new IntegerGuacamoleProperty() { + + @Override + public String getName() { return "postgresql-socket-timeout"; } + + }; + /** * Whether a user account within the database is required for authentication * to succeed, even if the user has been authenticated via another diff --git a/guacamole-docker/bin/start.sh b/guacamole-docker/bin/start.sh index 0d3b4618d..95b876381 100755 --- a/guacamole-docker/bin/start.sh +++ b/guacamole-docker/bin/start.sh @@ -354,10 +354,18 @@ END "postgresql-default-max-group-connections-per-user" \ "$POSTGRES_DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER" + set_optional_property \ + "postgresql-default-statement-timeout" \ + "$POSTGRES_DEFAULT_STATEMENT_TIMEOUT" + set_optional_property \ "postgresql-user-required" \ "$POSTGRES_USER_REQUIRED" + set_optional_property \ + "postgresql-socket-timeout" \ + "$POSTGRES_SOCKET_TIMEOUT" + set_optional_property \ "postgresql-ssl-mode" \ "$POSTGRESQL_SSL_MODE"