From 53c043a6b0f858e32aeec29821e311283d064787 Mon Sep 17 00:00:00 2001 From: Josef Rokos Date: Mon, 12 Oct 2026 15:47:36 +0200 Subject: [PATCH] Made database connection pool size configurable. Fixes #11 Co-Authored-By: Claude Opus 5.5 --- README.md | 4 ++++ config_sample.toml | 3 +++ src/config.rs | 35 ++++++++++++++++++++++++++++++++++- src/main.rs | 2 +- 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 38150b7..12f9769 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,10 @@ The server reads `config.toml` from the working directory, or from the path give The file contains the database and SMTP passwords and the session key. Keep it outside the site directory (`target/site`): everything in there is served as static files. The server refuses to start when the config file is inside it. +## Database connections + +Each instance opens database connections on demand, up to `max_connections` in the `[database]` section of the config (10 by default), and closes the ones that stay idle. When many instances share one PostgreSQL server, the sum of their limits must stay below the server's own `max_connections` (100 by default): lower the limit per instance, raise it on the server, or put PgBouncer in front of PostgreSQL. + ## First admin account On the first start, when the database has no admin account, the server creates the user `admin`. Its password must be given, at least 8 characters, in one of these ways: diff --git a/config_sample.toml b/config_sample.toml index a5ecfd3..2445e11 100644 --- a/config_sample.toml +++ b/config_sample.toml @@ -11,6 +11,9 @@ password = 'password' db_name = 'rezervator' host = 'localhost' port = 5432 +# Upper limit of open database connections, default is 10. Lower it when many instances +# share one PostgreSQL server. +#max_connections = 10 [mailing] transport = "File" #or Smtp diff --git a/src/config.rs b/src/config.rs index fef9cad..663d976 100644 --- a/src/config.rs +++ b/src/config.rs @@ -43,11 +43,18 @@ pub struct Database { password: String, db_name: String, host: String, - port: Option + port: Option, + max_connections: Option } #[cfg(feature = "ssr")] impl Database { + /// Upper limit of open database connections, 10 by default. With many instances on one + /// PostgreSQL server the sum of the limits must fit into its `max_connections`. + pub fn max_connections(&self) -> u32 { + self.max_connections.unwrap_or(10).max(1) + } + pub fn con_string(&self) -> String { format!("postgres://{}:{}@{}:{}/{}", self.user, self.password, self.host, self.port.unwrap_or(5432), self.db_name) } @@ -358,6 +365,32 @@ mod tests { assert_eq!(database.con_string(), "postgres://u:p@db.example.com:6543/db"); } + #[test] + fn max_connections_defaults_to_ten() { + let database: Database = toml::from_str( + "user = 'u'\npassword = 'p'\ndb_name = 'db'\nhost = 'localhost'").unwrap(); + + assert_eq!(database.max_connections(), 10); + // The sample config has the key commented out + assert_eq!(sample().database().max_connections(), 10); + } + + #[test] + fn max_connections_can_be_configured() { + let database: Database = toml::from_str( + "user = 'u'\npassword = 'p'\ndb_name = 'db'\nhost = 'localhost'\nmax_connections = 3").unwrap(); + + assert_eq!(database.max_connections(), 3); + } + + #[test] + fn max_connections_is_at_least_one() { + let database: Database = toml::from_str( + "user = 'u'\npassword = 'p'\ndb_name = 'db'\nhost = 'localhost'\nmax_connections = 0").unwrap(); + + assert_eq!(database.max_connections(), 1); + } + #[test] fn smtp_mailing_config() { let mailing: Mailing = toml::from_str( diff --git a/src/main.rs b/src/main.rs index cac7556..b5767b6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -77,7 +77,7 @@ async fn main() -> std::io::Result<()> { let key = Key::from(srv_conf.session().key()); let pool = PgPoolOptions::new() - .max_connections(10) + .max_connections(srv_conf.database().max_connections()) .connect(&srv_conf.database().con_string()).await.unwrap(); migrate!().run(&pool).await.expect("could not run SQLx migrations");