Loading…
Loading…
Configure database connection pools for the Admin API, including IAM and password authentication, and separate pools for application and migration tasks.
This document describes the database connection pool configuration for the Admin API service. The system uses HikariCP for connection pooling and provides robust, configurable data source management for connecting to a PostgreSQL database.
Two distinct connection pools are configured:
The configuration supports two primary authentication methods, allowing for flexible deployment across different environments:
Additionally, every connection from both pools is automatically tagged with a tenant identifier to support multi-tenancy at the database level.
The system defines two DataSource beans, dataSource and flywayDataSource, to manage database connections.
dataSource)This is the primary connection pool used by the service for handling all API requests and background tasks during normal operation. It is created by the dataSource() bean.
Key characteristics:
socketTimeout to prevent active connections from being permanently stuck during a network partition. If a read from the database socket hangs, the timeout will trigger, allowing the connection to be closed and the pool to recover.maxPoolSize and minIdle properties, with a minimum of 8 connections for maximumPoolSize and 1 for minimumIdle.maxLifetime) and are checked for liveness every 10 minutes (keepaliveTime) to maintain pool hygiene.flywayDataSource)This dedicated pool is used only when the service starts up to perform database schema migrations via Flyway. It is created by the flywayDataSource() bean and is marked with @FlywayDataSource.
Key characteristics:
CREATE INDEX CONCURRENTLY, can legitimately block for extended periods. A socket timeout could interrupt these operations mid-flight, potentially leaving the database schema in an inconsistent or invalid state and blocking future migrations.minimumIdle of 0 and an idleTimeout of 1 minute. This ensures that once migrations are complete, all connections are promptly closed, and the pool does not consume resources during normal application runtime.Both the application and migration pools are wrapped by a TenantBindingDataSource. This wrapper intercepts each connection as it is borrowed from the pool and executes a command to set the app.tenant_id session variable. This ensures that all database operations, whether from API requests or schema migrations, are associated with the correct tenant context, enabling features like Row-Level Security (RLS). The default tenant ID is used if no specific context is available.
The buildPool method determines which authentication strategy to use based on configuration properties and environment variables.
flowchart TD
A[Start Pool Creation] --> B{S2R_DB_IAM_AUTH_ENABLED is 'false'?};
B -- Yes --> P[Use Password Auth];
B -- No / Not Set --> C{authMode property is 'iam'?};
C -- Yes --> I[Use IAM Auth];
C -- No --> P;
subgraph IAM Auth
I --> I1[Verify S2R_DB_INSTANCE_CONNECTION_NAME is set];
I1 --> I2[Build JDBC URL for socket factory];
I2 --> I3[Configure Cloud SQL Socket Factory];
end
subgraph Password Auth
P --> P1[Verify S2R_DB_HOST is set];
P1 --> P2[Build standard host:port JDBC URL];
P2 --> P3[Set password from S2R_DB_PASSWORD];
endYou can select the authentication mode by setting the S2R_DB_IAM_AUTH_ENABLED environment variable or the authMode property.
This is the default authentication method. It relies on a specialized JDBC Socket Factory (com.google.cloud.sql.postgres.SocketFactory) to handle secure connectivity.
Mechanism:
To use this mode, S2R_DB_IAM_AUTH_ENABLED must not be set to false, and the authMode property must be iam.
Example JDBC URL:
jdbc:postgresql:///<database_name>
This mode uses a standard username and password to connect to the database. It is intended for environments where IAM authentication is not available, such as local development, containerized deployments, or other cloud providers.
Mechanism:
S2R_DB_IAM_AUTH_ENABLED to false or by setting the authMode property to password.host, port, and sslmode.Example JDBC URL:
jdbc:postgresql://<host>:<port>/<database_name>?sslmode=require
The following properties and environment variables are used to configure the database connection pools. Properties are accessed via the DbProperties configuration object.
| Parameter | Type | Default | Required | Description |
|---|---|---|---|---|
S2R_DB_IAM_AUTH_ENABLED | Environment Variable | true | No | If set to false, forces the use of password authentication, bypassing the IAM path. |
authMode | String | iam | No | Specifies the authentication mode. Can be iam or password. Overridden by S2R_DB_IAM_AUTH_ENABLED=false. |
user | String | — | Yes | The database username for the connection. Checked via S2R_DB_USER. |
password | String | — | Yes (for password auth) | The database password. Used only when password authentication is active. |
host | String | — | Yes (for password auth) | The database host name or IP address. Used only for password authentication. |
port | Integer | — | Yes (for password auth) | The database port number. |
name | String | — | Yes | The name of the database to connect to. |
sslMode | String | require | No (for password auth) | The SSL mode for the connection. Used only for password authentication. |
instanceConnectionName | String | — | Yes (for IAM auth) | The unique identifier for the database instance. Required for IAM authentication. |
ipType | String | PRIVATE | No (for IAM auth) | The IP address type to use for the connection (e.g., PRIVATE, PUBLIC). Used only for IAM authentication. |
maxPoolSize | Integer | — | Yes | The maximum number of connections in the application pool. The effective minimum is 8. |
minIdle | Integer | — | Yes | The minimum number of idle connections in the application pool. The effective minimum is 1. |
connectionTimeoutMs | Long | — | Yes | The connection timeout in milliseconds. The effective minimum is 3000. |
validationTimeoutMs | Long | — | Yes | The connection validation timeout in milliseconds. The effective minimum is 2000. |
socketTimeoutSeconds | Integer | — | Yes | The socket read timeout in seconds for the application pool. |
connectTimeoutSeconds | Integer | — | Yes | The socket connect timeout in seconds, applied to both pools. |
NOTE
The source defines several hard-coded values for pool behavior:
maxLifetime is 30 minutes, keepaliveTime is 10 minutes.maximumPoolSize is 4, minimumIdle is 0, idleTimeout is 1 minute, and socketTimeout is disabled.initializationFailTimeout is -1, allowing the application to wait indefinitely for the database on startup.The service will fail to start if required configuration is missing.
java.lang.IllegalStateException: S2R_DB_USER must be configured
java.lang.IllegalStateException: S2R_DB_INSTANCE_CONNECTION_NAME required for IAM auth
java.lang.IllegalStateException: S2R_DB_HOST must be configured for password auth
Application Hangs During Network Partition:
socketTimeout, active connections could get stuck in a read operation on a dead socket. The pool would exhaust all connections and be unable to recover even after the network was restored.socketTimeoutSeconds property on the application pool ensures that stuck connections are eventually terminated, allowing the pool to self-heal by creating new, healthy connections.Migration Deadlocks or Failures:
WARNING
Do Not Set a Socket Timeout on the Migration Pool
The flywayDataSource is intentionally configured without a socket timeout. Long-running DDL operations like CREATE INDEX CONCURRENTLY are expected to block for significant periods. Applying a short timeout can cause the migration to be aborted, which may leave the database with an INVALID index or a corrupt schema history, preventing all future migrations from running.