Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
376 changes: 173 additions & 203 deletions .schema/pgdog.schema.json

Large diffs are not rendered by default.

80 changes: 55 additions & 25 deletions .schema/users.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,21 @@
}
]
},
"TimeValue": {
"description": "Time value: a number, in the unit documented on the field, or a duration\nstring built from `ms`, `s`, `m`, `h` and `d` components, e.g. `\"1h5m15s\"`.",
"anyOf": [
{
"description": "Number of milliseconds, or seconds for fields documented in seconds.",
"type": "integer",
"format": "uint64",
"minimum": 0
},
{
"description": "Duration string, e.g. `\"250ms\"`, `\"5s\"`, `\"1h5m15s\"`.",
"type": "string"
}
]
},
"User": {
"description": "User allowed to connect to pgDog.\nA user entry in `users.toml`, controlling which users are allowed to connect to PgDog.\n\n<https://docs.pgdog.dev/configuration/users.toml/users/>",
"type": "object",
Expand Down Expand Up @@ -136,21 +151,27 @@
},
"idle_timeout": {
"description": "Overrides [`idle_timeout`](https://docs.pgdog.dev/configuration/pgdog.toml/general/#idle_timeout) for this user. Server connections that have been idle for this long, without affecting [`min_pool_size`](https://docs.pgdog.dev/configuration/pgdog.toml/general/#min_pool_size), will be closed.\n\n<https://docs.pgdog.dev/configuration/users.toml/users/#idle_timeout>",
"type": [
"integer",
"null"
"anyOf": [
{
"$ref": "#/$defs/TimeValue"
},
{
"type": "null"
}
],
"format": "uint64",
"minimum": 0
"default": null
},
"lock_timeout": {
"description": "Lock timeout.\n\nSets the `lock_timeout` on all server connections at connection creation.\nAborts any statement that waits longer than the specified duration to acquire a lock.\nUnlike `statement_timeout`, this only counts time spent waiting for locks, not execution time.\nRecommended for replication destination connections to prevent cross-shard deadlocks\nfrom hanging indefinitely.\n\n**Note:** Nothing is preventing the user from manually changing this setting at runtime,\ne.g., by running `SET lock_timeout TO 0`;\n\n<https://docs.pgdog.dev/configuration/users.toml/users/#lock_timeout>",
"type": [
"integer",
"null"
"anyOf": [
{
"$ref": "#/$defs/TimeValue"
},
{
"type": "null"
}
],
"format": "uint64",
"minimum": 0
"default": null
},
"min_pool_size": {
"description": "Overrides [`min_pool_size`](https://docs.pgdog.dev/configuration/pgdog.toml/general/#min_pool_size) for this user. Opens at least this many connections on pooler startup and keeps them open despite [`idle_timeout`](https://docs.pgdog.dev/configuration/pgdog.toml/general/#idle_timeout).\n\n<https://docs.pgdog.dev/configuration/users.toml/users/#min_pool_size>",
Expand Down Expand Up @@ -245,21 +266,27 @@
},
"server_lifetime": {
"description": "Server connections older than this (in milliseconds) will be closed when returned to the pool.",
"type": [
"integer",
"null"
"anyOf": [
{
"$ref": "#/$defs/TimeValue"
},
{
"type": "null"
}
],
"format": "uint64",
"minimum": 0
"default": null
},
"server_lifetime_jitter": {
"description": "Maximum random adjustment applied to `server_lifetime` per backend connection (milliseconds).\nOverrides the database-level and general-level `server_lifetime_jitter` setting for this user.",
"type": [
"integer",
"null"
"anyOf": [
{
"$ref": "#/$defs/TimeValue"
},
{
"type": "null"
}
],
"format": "uint64",
"minimum": 0
"default": null
},
"server_password": {
"description": "Which password to connect with when creating backend connections from PgDog to PostgreSQL. By default, the password configured in `password` is used. This setting allows you to override this configuration and use a different password, decoupling server passwords from user passwords given to clients.\n\n**Note:** Values specified in `pgdog.toml` take priority over this configuration.\n\n<https://docs.pgdog.dev/configuration/users.toml/users/#server_password>",
Expand All @@ -284,12 +311,15 @@
},
"statement_timeout": {
"description": "Statement timeout.\n\nSets the `statement_timeout` on all server connections at connection creation. This allows you to set a reasonable default for each user without modifying `postgresql.conf` or using `ALTER USER`.\n\n**Note:** Nothing is preventing the user from manually changing this setting at runtime, e.g., by running `SET statement_timeout TO 0`;\n\n<https://docs.pgdog.dev/configuration/users.toml/users/#statement_timeout>",
"type": [
"integer",
"null"
"anyOf": [
{
"$ref": "#/$defs/TimeValue"
},
{
"type": "null"
}
],
"format": "uint64",
"minimum": 0
"default": null
},
"two_phase_commit": {
"description": "Overrides [`two_phase_commit`](https://docs.pgdog.dev/configuration/pgdog.toml/general/#two_phase_commit) for this user.\n\n<https://docs.pgdog.dev/configuration/users.toml/users/#two_phase_commit>",
Expand Down
3 changes: 3 additions & 0 deletions example.pgdog.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
#
# Most settings have reasonable defaults.
#
# Time settings accept a number, in the unit documented for the setting, or a
# duration string built from "ms", "s", "m", "h" and "d", e.g. "5s", "1h5m15s".
#

# General settings.
#
Expand Down
98 changes: 98 additions & 0 deletions pgdog-config/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,104 @@ mod tests {
use std::time::Duration;
use tempfile::NamedTempFile;

#[test]
fn test_human_durations() {
let source = r#"
[general]
ban_timeout = "5m"
checkout_timeout = "2s500ms"
query_timeout = "1h5m15s"
shutdown_termination_timeout = "30s"
idle_timeout = 60000
two_phase_commit_wal_checkpoint_interval = "2m"

[[databases]]
name = "production"
host = "127.0.0.1"
database_name = "postgres"
statement_timeout = "1m30s"

[tcp]
time = "1s"
interval = "500ms"
user_timeout = 1000

[replica_lag]
check_interval = "1s"
max_age = "25ms"

[otel]
push_interval = "10s"

[vault]
url = "http://127.0.0.1:8200"
auth_method = "kubernetes"
client_token_ttl = "5m"
"#;

let config: Config = toml::from_str(source).unwrap();
let general = &config.general;

assert_eq!(general.ban_timeout, 300_000);
assert_eq!(general.checkout_timeout, 2_500);
assert_eq!(general.query_timeout, 3_915_000);
assert_eq!(general.shutdown_termination_timeout, Some(30_000));
assert_eq!(general.idle_timeout, 60_000);
assert_eq!(general.two_phase_commit_wal_checkpoint_interval, 120);

assert_eq!(config.databases[0].statement_timeout, Some(90_000));
assert_eq!(config.tcp.time(), Some(Duration::from_secs(1)));
assert_eq!(config.tcp.interval(), Some(Duration::from_millis(500)));
assert_eq!(config.tcp.user_timeout(), Some(Duration::from_secs(1)));

let replica_lag = config.replica_lag.unwrap();
assert_eq!(replica_lag.check_interval, Duration::from_secs(1));
assert_eq!(replica_lag.max_age, Duration::from_millis(25));

assert_eq!(config.otel.push_interval, 10_000);
assert_eq!(config.vault.unwrap().client_token_ttl, Some(300));
}

#[test]
fn test_human_durations_users() {
let source = r#"
[[users]]
name = "alice"
database = "production"
statement_timeout = "10s"
idle_timeout = "1h"
server_lifetime = "1d"
server_lifetime_jitter = 5000
"#;

let users: Users = toml::from_str(source).unwrap();
let user = &users.users[0];

assert_eq!(user.statement_timeout, Some(10_000));
assert_eq!(user.idle_timeout, Some(3_600_000));
assert_eq!(user.server_lifetime, Some(86_400_000));
assert_eq!(user.server_lifetime_jitter, Some(5_000));
}

#[test]
fn test_human_durations_invalid() {
let source = r#"
[general]
ban_timeout = "5 minutes"
"#;

let err = toml::from_str::<Config>(source).unwrap_err().to_string();
assert!(err.contains("is not a valid duration"), "{}", err);

let source = r#"
[general]
two_phase_commit_wal_checkpoint_interval = "1500ms"
"#;

let err = toml::from_str::<Config>(source).unwrap_err().to_string();
assert!(err.contains("whole number of seconds"), "{}", err);
}

#[test]
fn test_basic() {
let pgdog_source = r#"
Expand Down
10 changes: 10 additions & 0 deletions pgdog-config/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,16 +178,22 @@ pub struct Database {
/// This setting configures the `statement_timeout` connection parameter on all connections to Postgres for this database.
///
/// <https://docs.pgdog.dev/configuration/pgdog.toml/databases/#statement_timeout>
#[serde(default, deserialize_with = "crate::duration::millis_optional")]
#[schemars(with = "Option<crate::duration::TimeValue>")]
pub statement_timeout: Option<u64>,
/// This setting configures the `lock_timeout` connection parameter on all connections to Postgres for this database.
/// Aborts any statement that waits longer than the specified duration to acquire a lock.
/// Unlike `statement_timeout`, this only counts time spent waiting for locks, not execution time.
///
/// <https://docs.pgdog.dev/configuration/pgdog.toml/databases/#lock_timeout>
#[serde(default, deserialize_with = "crate::duration::millis_optional")]
#[schemars(with = "Option<crate::duration::TimeValue>")]
pub lock_timeout: Option<u64>,
/// Overrides the `idle_timeout` setting. Idle server connections exceeding this timeout will be closed automatically.
///
/// <https://docs.pgdog.dev/configuration/pgdog.toml/databases/#idle_timeout>
#[serde(default, deserialize_with = "crate::duration::millis_optional")]
#[schemars(with = "Option<crate::duration::TimeValue>")]
pub idle_timeout: Option<u64>,
/// Sets the `default_transaction_read_only` connection parameter to `on` on all server connections to this database. Clients can still override it with `SET`.
///
Expand All @@ -196,10 +202,14 @@ pub struct Database {
/// Overrides the `server_lifetime` setting. Server connections older than this will be closed when returned to the pool.
///
/// <https://docs.pgdog.dev/configuration/pgdog.toml/databases/#server_lifetime>
#[serde(default, deserialize_with = "crate::duration::millis_optional")]
#[schemars(with = "Option<crate::duration::TimeValue>")]
pub server_lifetime: Option<u64>,
/// Overrides the `server_lifetime_jitter` setting for this database.
///
/// <https://docs.pgdog.dev/configuration/pgdog.toml/databases/#server_lifetime_jitter>
#[serde(default, deserialize_with = "crate::duration::millis_optional")]
#[schemars(with = "Option<crate::duration::TimeValue>")]
pub server_lifetime_jitter: Option<u64>,
/// Used for resharding only; this database will not serve regular traffic.
#[serde(default)]
Expand Down
Loading
Loading