From bd205d22509c6969d8ff452cab29d764ee50ee7f Mon Sep 17 00:00:00 2001 From: Hampus Date: Mon, 31 Aug 2026 19:00:43 +0200 Subject: [PATCH] fix(app-proxy): honour the shared Postgres settings (#2262) --- deploy/self-hosting/docker-compose.yml | 21 ++++--- fluxer_app_proxy/src/config.rs | 76 ++++++++++++++++++++++++-- 2 files changed, 84 insertions(+), 13 deletions(-) diff --git a/deploy/self-hosting/docker-compose.yml b/deploy/self-hosting/docker-compose.yml index ba489bc41..abbc953f6 100644 --- a/deploy/self-hosting/docker-compose.yml +++ b/deploy/self-hosting/docker-compose.yml @@ -1,6 +1,17 @@ name: fluxer +x-fluxer-postgres-env: &fluxer-postgres-env + FLUXER_DATABASE_BACKEND: postgres + FLUXER_POSTGRES_HOST: postgres + FLUXER_POSTGRES_PORT: "5432" + FLUXER_POSTGRES_DATABASE: fluxer + FLUXER_POSTGRES_USERNAME: fluxer + FLUXER_POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env} + FLUXER_POSTGRES_SSL: "false" + FLUXER_POSTGRES_PREPARED_STATEMENTS: ${FLUXER_POSTGRES_PREPARED_STATEMENTS:-true} + x-fluxer-env: &fluxer-env + <<: *fluxer-postgres-env FLUXER_ENV: production NODE_ENV: production FLUXER_SELF_HOSTED: "true" @@ -12,15 +23,6 @@ x-fluxer-env: &fluxer-env FLUXER_API_HEADERS_TIMEOUT_MS: ${FLUXER_API_HEADERS_TIMEOUT_MS:-30000} FLUXER_API_REQUEST_TIMEOUT_MS: ${FLUXER_API_REQUEST_TIMEOUT_MS:-120000} - FLUXER_DATABASE_BACKEND: postgres - FLUXER_POSTGRES_HOST: postgres - FLUXER_POSTGRES_PORT: "5432" - FLUXER_POSTGRES_DATABASE: fluxer - FLUXER_POSTGRES_USERNAME: fluxer - FLUXER_POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env} - FLUXER_POSTGRES_SSL: "false" - FLUXER_POSTGRES_PREPARED_STATEMENTS: ${FLUXER_POSTGRES_PREPARED_STATEMENTS:-true} - FLUXER_KV_URL: redis://valkey:6379/0 FLUXER_NATS_URL: nats://nats:4222 FLUXER_NATS_JETSTREAM_URL: nats://nats:4222 @@ -412,6 +414,7 @@ services: limits: memory: ${FLUXER_APP_PROXY_MEMORY_LIMIT:-256mb} environment: + <<: *fluxer-postgres-env FLUXER_APP_PROXY_HOST: 0.0.0.0 FLUXER_APP_PROXY_PORT: "8080" DISCOVERY_UPSTREAM_URL: http://caddy:8088/api/.well-known/fluxer diff --git a/fluxer_app_proxy/src/config.rs b/fluxer_app_proxy/src/config.rs index 072dac777..9a12a24e8 100644 --- a/fluxer_app_proxy/src/config.rs +++ b/fluxer_app_proxy/src/config.rs @@ -251,10 +251,7 @@ impl AppProxyConfig { postgres_ssl_ca: cfg::non_empty_env("FLUXER_POSTGRES_SSL_CA"), postgres_max_connections, postgres_kv_table: cfg::read_env("FLUXER_POSTGRES_KV_TABLE", "fluxer_kv"), - postgres_prepared_statements: cfg::read_bool_env( - &["FLUXER_POSTGRES_PREPARED_STATEMENTS"], - true, - ), + postgres_prepared_statements: resolve_postgres_prepared_statements_from_env(), } } } @@ -274,6 +271,10 @@ fn resolve_time_freeze_enabled_from_env() -> bool { resolve_time_freeze_enabled(|name| env::var(name).ok()) } +fn resolve_postgres_prepared_statements_from_env() -> bool { + resolve_postgres_prepared_statements(|name| env::var(name).ok()) +} + fn resolve_time_freeze_enabled(mut read_var: F) -> bool where F: FnMut(&str) -> Option, @@ -292,6 +293,31 @@ fn parse_boolish(value: &str) -> bool { ) } +fn resolve_postgres_prepared_statements(mut read_var: F) -> bool +where + F: FnMut(&str) -> Option, +{ + let Some(value) = read_var("FLUXER_POSTGRES_PREPARED_STATEMENTS") + .map(|value| value.trim().to_ascii_lowercase()) + .filter(|value| !value.is_empty()) + else { + return true; + }; + + match value.as_str() { + "1" | "true" | "yes" | "y" | "on" => true, + "0" | "false" | "no" | "n" | "off" => false, + other => { + tracing::warn!( + env = "FLUXER_POSTGRES_PREPARED_STATEMENTS", + value = other, + "invalid value; falling back to default" + ); + true + } + } +} + fn resolve_discovery_upstream_url(mut read_var: F) -> String where F: FnMut(&str) -> Option, @@ -342,6 +368,11 @@ mod tests { resolve_time_freeze_enabled(|name| env.get(name).map(|value| value.to_string())) } + fn resolve_prepared_statements_from_pairs(pairs: &[(&str, &str)]) -> bool { + let env: HashMap<&str, &str> = pairs.iter().copied().collect(); + resolve_postgres_prepared_statements(|name| env.get(name).map(|value| value.to_string())) + } + #[test] fn csp_config_default_has_no_extra_sources() { let c = CspConfig::default(); @@ -429,6 +460,43 @@ mod tests { ); } + #[test] + fn a_set_but_empty_prepared_statements_value_keeps_the_shared_default() { + assert!(resolve_prepared_statements_from_pairs(&[])); + assert!( + resolve_prepared_statements_from_pairs(&[("FLUXER_POSTGRES_PREPARED_STATEMENTS", "")]), + "an empty value disabled named statements here while every other service kept them" + ); + assert!(resolve_prepared_statements_from_pairs(&[( + "FLUXER_POSTGRES_PREPARED_STATEMENTS", + " ", + )])); + } + + #[test] + fn an_explicit_prepared_statements_value_is_honoured() { + assert!(!resolve_prepared_statements_from_pairs(&[( + "FLUXER_POSTGRES_PREPARED_STATEMENTS", + "false", + )])); + assert!(!resolve_prepared_statements_from_pairs(&[( + "FLUXER_POSTGRES_PREPARED_STATEMENTS", + "OFF", + )])); + assert!(resolve_prepared_statements_from_pairs(&[( + "FLUXER_POSTGRES_PREPARED_STATEMENTS", + "yes", + )])); + } + + #[test] + fn a_non_boolean_prepared_statements_value_keeps_the_shared_default() { + assert!(resolve_prepared_statements_from_pairs(&[( + "FLUXER_POSTGRES_PREPARED_STATEMENTS", + "maybe", + )])); + } + #[test] fn time_freeze_enabled_by_default_for_hosted_runtime() { assert!(resolve_time_freeze_from_pairs(&[]));