Skip to content

Commit 1314bdf

Browse files
committed
fix(db): support libpq keyword/value connection strings
addKeepaliveParams blindly appended `?keepalives=…` to the connection string, which only works for URI form. With docker-compose's `DATABASE_URL=host=… sslmode=disable`, the `?` was swallowed by the last keyword's value, yielding libpq error: `invalid sslmode value: "disable?keepalives=1&..."`. Added appendConnParams that detects URI vs keyword/value form and uses the correct separator (`?`/`&` vs space). Also routed the TimescaleDB `options` append through it so fresh docker-compose boots work.
1 parent 84c4ed3 commit 1314bdf

2 files changed

Lines changed: 27 additions & 5 deletions

File tree

src/Pkg/DeriveUtils.hs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ module Pkg.DeriveUtils (
1212
encodeEnumSC,
1313
WrappedEnumShow (..),
1414
addKeepaliveParams,
15+
appendConnParams,
1516
connectPostgreSQL,
1617
idToText,
1718
idFromText,
@@ -29,6 +30,7 @@ module Pkg.DeriveUtils (
2930
import Control.Exception (throwIO)
3031
import Control.Lens ((?~))
3132
import Data.Aeson qualified as AE
33+
import Data.ByteString qualified as BS
3234
import Data.Aeson.KeyMap qualified as KEM
3335
import Data.Aeson.Types qualified as AET
3436
import Data.CaseInsensitive (CI, FoldCase)
@@ -319,11 +321,28 @@ data BaselineState = BSLearning | BSEstablished
319321
deriving (AE.FromJSON, AE.ToJSON, FromField, HI.DecodeValue, HI.EncodeValue, ToField) via WrappedEnumSC "BS" BaselineState
320322

321323

324+
-- | Append libpq connection parameters, handling both URI
325+
-- (@postgres://…?k=v&…@) and keyword/value (@host=… sslmode=…@) forms.
326+
appendConnParams :: [(ByteString, ByteString)] -> ByteString -> ByteString
327+
appendConnParams kvs connStr
328+
| null kvs = connStr
329+
| isUri =
330+
let sep = if "?" `T.isInfixOf` decodeUtf8 connStr then "&" else "?"
331+
in connStr <> sep <> BS.intercalate "&" [k <> "=" <> v | (k, v) <- kvs]
332+
| otherwise = connStr <> " " <> BS.intercalate " " [k <> "=" <> v | (k, v) <- kvs]
333+
where
334+
txt = decodeUtf8 connStr
335+
isUri = "postgres://" `T.isPrefixOf` txt || "postgresql://" `T.isPrefixOf` txt
336+
337+
322338
addKeepaliveParams :: ByteString -> ByteString
323-
addKeepaliveParams connStr =
324-
let params = "keepalives=1&keepalives_idle=15&keepalives_interval=10&keepalives_count=3"
325-
sep = if T.isInfixOf "?" (decodeUtf8 connStr) then "&" else "?"
326-
in connStr <> sep <> params
339+
addKeepaliveParams =
340+
appendConnParams
341+
[ ("keepalives", "1")
342+
, ("keepalives_idle", "15")
343+
, ("keepalives_interval", "10")
344+
, ("keepalives_count", "3")
345+
]
327346

328347

329348
connectPostgreSQL :: ByteString -> IO Connection

src/System/Config.hs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,10 @@ configToEnv :: IOE :> es => EnvConfig -> Eff es AuthContext
253253
configToEnv config = do
254254
let createPgConnIO = PG.connectPostgreSQL $ DeriveUtils.addKeepaliveParams $ encodeUtf8 config.databaseUrl
255255
-- Raise TimescaleDB DML decompression limit for UPDATE queries on compressed hypertables
256-
tfParams = DeriveUtils.addKeepaliveParams (encodeUtf8 config.timefusionPgUrl) <> "&options=-c%20timescaledb.max_tuples_decompressed_per_dml_transaction%3D0"
256+
tfParams =
257+
DeriveUtils.appendConnParams
258+
[("options", "-c%20timescaledb.max_tuples_decompressed_per_dml_transaction%3D0")]
259+
(DeriveUtils.addKeepaliveParams (encodeUtf8 config.timefusionPgUrl))
257260
let createTimefusionPgConnIO = DeriveUtils.connectPostgreSQL tfParams
258261
when config.migrateAndInitializeOnStart $ liftIO do
259262
conn <- createPgConnIO

0 commit comments

Comments
 (0)