diff --git a/CHANGELOG.md b/CHANGELOG.md index 07c2da9..857db6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,25 @@ ## Unreleased +- You can now use the `PGCONNECT_TIMEOUT` variable to set the maximum time in + seconds to wait while connecting: + + ```bash + # Wait at most 5 seconds before timing out when connecting to the database. + export PGCONNECT_TIMEOUT=5 + gleam run -m squirrel + ``` + + You can also change the timeout value when using a connection string, by + setting the `connect_timeout` query parameter: + + ```bash + export DATABASE_URL="postgres://user@host:5432/my_db?connect_timeout=5" + gleam run -m squirrel + ``` + + ([Giacomo Cavalieri](https://github.com/giacomocavalieri)) + - Updated code for `gleam_stdlib` `>= 0.61.0 and < 1.0.0`. ([Giacomo Cavalieri](https://github.com/giacomocavalieri)) diff --git a/README.md b/README.md index 1f2010c..bf26967 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,7 @@ the Postgres server where the database is defined. To connect, it will read the following format: ```txt -postgres://user:password@host:port/database +postgres://user:password@host:port/database?connect_timeout=seconds ``` If a `DATABASE_URL` variable is not set, Squirrel will instead read your @@ -177,6 +177,7 @@ and use the following defaults if one is not set: - `PGUSER`: `"postgres"` - `PGDATABASE`: the name of your Gleam project - `PGPASSWORD`: `""` +- `PGCONNECT_TIMEOUT`: `5` seconds ## Supported types diff --git a/src/squirrel.gleam b/src/squirrel.gleam index 294ce98..b480266 100644 --- a/src/squirrel.gleam +++ b/src/squirrel.gleam @@ -180,7 +180,7 @@ const default_password = "" const default_port = 5432 -const default_timeout = 1000 +const default_timeout = 5 /// Creates a `ConnectionOptions` reading values from env variables and falling /// back to some defaults if any required one is not set. @@ -197,6 +197,10 @@ fn connection_options_from_variables() -> postgres.ConnectionOptions { envoy.get("PGPORT") |> result.try(int.parse) |> result.unwrap(default_port) + let timeout_seconds = + envoy.get("PGCONNECT_TIMEOUT") + |> result.try(int.parse) + |> result.unwrap(default_timeout) postgres.ConnectionOptions( host:, @@ -204,7 +208,7 @@ fn connection_options_from_variables() -> postgres.ConnectionOptions { user:, password:, database:, - timeout: default_timeout, + timeout_seconds:, ) } @@ -213,10 +217,19 @@ fn connection_options_from_variables() -> postgres.ConnectionOptions { /// fn parse_connection_url(raw: String) -> Result(postgres.ConnectionOptions, Nil) { use uri <- result.try(uri.parse(raw)) - let Uri(scheme:, userinfo:, host:, port:, path:, ..) = uri + let Uri(scheme:, userinfo:, host:, port:, path:, query:, ..) = uri + + use parameters <- result.try(case query { + None -> Ok([]) + Some(parameters) -> uri.parse_query(parameters) + }) use _ <- result.try(check_scheme(scheme)) let #(user, password) = parse_user_and_password_from_userinfo(userinfo) let database = parse_database_from_path(path) + use timeout <- result.try(case list.key_find(parameters, "connect_timeout") { + Error(_) -> Ok(default_timeout) + Ok(timeout) -> int.parse(timeout) + }) Ok(postgres.ConnectionOptions( host: host |> option.unwrap(default_host), @@ -224,7 +237,7 @@ fn parse_connection_url(raw: String) -> Result(postgres.ConnectionOptions, Nil) user: user |> option.unwrap(default_user), password: password |> option.unwrap(default_password), database: database |> option.unwrap(default_database), - timeout: default_timeout, + timeout_seconds: timeout, )) } diff --git a/src/squirrel/internal/database/postgres.gleam b/src/squirrel/internal/database/postgres.gleam index 0757f77..bbad097 100644 --- a/src/squirrel/internal/database/postgres.gleam +++ b/src/squirrel/internal/database/postgres.gleam @@ -249,7 +249,7 @@ pub type ConnectionOptions { user: String, password: String, database: String, - timeout: Int, + timeout_seconds: Int, ) } @@ -305,11 +305,17 @@ pub fn main( queries: List(UntypedQuery), connection: ConnectionOptions, ) -> Result(#(List(TypedQuery), List(Error)), Error) { - let ConnectionOptions(host:, port:, timeout:, user:, password:, database:) = - connection + let ConnectionOptions( + host:, + port:, + timeout_seconds:, + user:, + password:, + database:, + ) = connection use db <- result.try( - pg.connect(host, port, timeout) + pg.connect(host, port, timeout_seconds * 1000) |> result.map_error(error.PgCannotEstablishTcpConnection( host: host, port: port, diff --git a/test/squirrel_test.gleam b/test/squirrel_test.gleam index 7467bc4..d90cc9b 100644 --- a/test/squirrel_test.gleam +++ b/test/squirrel_test.gleam @@ -233,7 +233,7 @@ fn type_queries( user: user, database: database, password: "", - timeout: 1000, + timeout_seconds: 1, ), ) }