feat: use hasql-pool-0.9, add db-pool-max-lifetime (fixes #2638)
- db-pool-acquisition-timeout is no longer optional, defaults to 10s - new option db-pool-max-lifetime limits the maximal lifetime of a postgresql connection, defaults to 30m
This commit is contained in:
committed by
steve-chavez
parent
b869dd7be9
commit
f26cdd5151
@@ -5,6 +5,13 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- #2663, Limit maximal postgresql connection lifetime - @robx
|
||||||
|
+ New option `db-pool-max-lifetime` (default 30m)
|
||||||
|
+ `db-pool-acquisition-timeout` is no longer optional and defaults to 10s
|
||||||
|
+ Fixes postgresql resource leak with long-lived connections (#2638)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- #2667, Fix `db-pool-acquisition-timeout` not logging to stderr when the timeout is reached - @steve-chavez
|
- #2667, Fix `db-pool-acquisition-timeout` not logging to stderr when the timeout is reached - @steve-chavez
|
||||||
|
|||||||
@@ -38,6 +38,24 @@ let
|
|||||||
sha256 = "1wmyhldk0k14y8whp1p4akrkqxf5snh8qsbm7fv5f7kz95nyffd0";
|
sha256 = "1wmyhldk0k14y8whp1p4akrkqxf5snh8qsbm7fv5f7kz95nyffd0";
|
||||||
})
|
})
|
||||||
{ });
|
{ });
|
||||||
|
|
||||||
|
hasql-notifications = lib.dontCheck
|
||||||
|
(prev.callHackageDirect
|
||||||
|
{
|
||||||
|
pkg = "hasql-notifications";
|
||||||
|
ver = "0.2.0.4";
|
||||||
|
sha256 = "sha256-fm1xiDyvDkb5WLOJ73/s8wrWEW23XFS7luAv2brfr8I=";
|
||||||
|
}
|
||||||
|
{ });
|
||||||
|
|
||||||
|
hasql-pool = lib.dontCheck
|
||||||
|
(prev.callHackageDirect
|
||||||
|
{
|
||||||
|
pkg = "hasql-pool";
|
||||||
|
ver = "0.9";
|
||||||
|
sha256 = "sha256-5UshbbaBVY8eJ/9VagNVVxonRwMcd7UmGqDc35pJNFY=";
|
||||||
|
}
|
||||||
|
{ });
|
||||||
} // extraOverrides final prev;
|
} // extraOverrides final prev;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
|||||||
+3
-3
@@ -90,7 +90,7 @@ library
|
|||||||
, hasql >= 1.6.1.1 && < 1.7
|
, hasql >= 1.6.1.1 && < 1.7
|
||||||
, hasql-dynamic-statements >= 0.3.1 && < 0.4
|
, hasql-dynamic-statements >= 0.3.1 && < 0.4
|
||||||
, hasql-notifications >= 0.1 && < 0.3
|
, hasql-notifications >= 0.1 && < 0.3
|
||||||
, hasql-pool >= 0.8.0.6 && < 0.9
|
, hasql-pool >= 0.9 && < 0.10
|
||||||
, hasql-transaction >= 1.0.1 && < 1.1
|
, hasql-transaction >= 1.0.1 && < 1.1
|
||||||
, heredoc >= 0.2 && < 0.3
|
, heredoc >= 0.2 && < 0.3
|
||||||
, http-types >= 0.12.2 && < 0.13
|
, http-types >= 0.12.2 && < 0.13
|
||||||
@@ -228,7 +228,7 @@ test-suite spec
|
|||||||
, bytestring >= 0.10.8 && < 0.12
|
, bytestring >= 0.10.8 && < 0.12
|
||||||
, case-insensitive >= 1.2 && < 1.3
|
, case-insensitive >= 1.2 && < 1.3
|
||||||
, containers >= 0.5.7 && < 0.7
|
, containers >= 0.5.7 && < 0.7
|
||||||
, hasql-pool >= 0.8.0.2 && < 0.9
|
, hasql-pool >= 0.9 && < 0.10
|
||||||
, hasql-transaction >= 1.0.1 && < 1.1
|
, hasql-transaction >= 1.0.1 && < 1.1
|
||||||
, heredoc >= 0.2 && < 0.3
|
, heredoc >= 0.2 && < 0.3
|
||||||
, hspec >= 2.3 && < 2.10
|
, hspec >= 2.3 && < 2.10
|
||||||
@@ -247,7 +247,7 @@ test-suite spec
|
|||||||
, transformers-base >= 0.4.4 && < 0.5
|
, transformers-base >= 0.4.4 && < 0.5
|
||||||
, wai >= 3.2.1 && < 3.3
|
, wai >= 3.2.1 && < 3.3
|
||||||
, wai-extra >= 3.0.19 && < 3.2
|
, wai-extra >= 3.0.19 && < 3.2
|
||||||
ghc-options: -O0 -Werror -Wall -fwarn-identities
|
ghc-options: -threaded -O0 -Werror -Wall -fwarn-identities
|
||||||
-fno-spec-constr -optP-Wno-nonportable-include-path
|
-fno-spec-constr -optP-Wno-nonportable-include-path
|
||||||
-fno-warn-missing-signatures
|
-fno-warn-missing-signatures
|
||||||
-fwrite-ide-info
|
-fwrite-ide-info
|
||||||
|
|||||||
@@ -116,10 +116,11 @@ destroy = destroyPool
|
|||||||
|
|
||||||
initPool :: AppConfig -> IO SQL.Pool
|
initPool :: AppConfig -> IO SQL.Pool
|
||||||
initPool AppConfig{..} =
|
initPool AppConfig{..} =
|
||||||
SQL.acquire configDbPoolSize timeoutMilliseconds $ toUtf8 configDbUri
|
SQL.acquire
|
||||||
where
|
configDbPoolSize
|
||||||
timeoutMilliseconds = (* oneSecond) <$> configDbPoolAcquisitionTimeout
|
(fromIntegral configDbPoolAcquisitionTimeout)
|
||||||
oneSecond = 1000000
|
(fromIntegral configDbPoolMaxLifetime)
|
||||||
|
(toUtf8 configDbUri)
|
||||||
|
|
||||||
-- | Run an action with a database connection.
|
-- | Run an action with a database connection.
|
||||||
usePool :: AppState -> SQL.Session a -> IO (Either SQL.UsageError a)
|
usePool :: AppState -> SQL.Session a -> IO (Either SQL.UsageError a)
|
||||||
|
|||||||
@@ -151,6 +151,9 @@ exampleConfigFile =
|
|||||||
|## Time in seconds to wait to acquire a slot from the connection pool
|
|## Time in seconds to wait to acquire a slot from the connection pool
|
||||||
|# db-pool-acquisition-timeout = 10
|
|# db-pool-acquisition-timeout = 10
|
||||||
|
|
|
|
||||||
|
|## Time in seconds after which to recycle pool connections
|
||||||
|
|# db-pool-max-lifetime = 1800
|
||||||
|
|
|
||||||
|## Stored proc to exec immediately after auth
|
|## Stored proc to exec immediately after auth
|
||||||
|# db-pre-request = "stored_proc_name"
|
|# db-pre-request = "stored_proc_name"
|
||||||
|
|
|
|
||||||
|
|||||||
@@ -70,7 +70,8 @@ data AppConfig = AppConfig
|
|||||||
, configDbMaxRows :: Maybe Integer
|
, configDbMaxRows :: Maybe Integer
|
||||||
, configDbPlanEnabled :: Bool
|
, configDbPlanEnabled :: Bool
|
||||||
, configDbPoolSize :: Int
|
, configDbPoolSize :: Int
|
||||||
, configDbPoolAcquisitionTimeout :: Maybe Int
|
, configDbPoolAcquisitionTimeout :: Int
|
||||||
|
, configDbPoolMaxLifetime :: Int
|
||||||
, configDbPreRequest :: Maybe QualifiedIdentifier
|
, configDbPreRequest :: Maybe QualifiedIdentifier
|
||||||
, configDbPreparedStatements :: Bool
|
, configDbPreparedStatements :: Bool
|
||||||
, configDbRootSpec :: Maybe QualifiedIdentifier
|
, configDbRootSpec :: Maybe QualifiedIdentifier
|
||||||
@@ -130,7 +131,8 @@ toText conf =
|
|||||||
,("db-max-rows", maybe "\"\"" show . configDbMaxRows)
|
,("db-max-rows", maybe "\"\"" show . configDbMaxRows)
|
||||||
,("db-plan-enabled", T.toLower . show . configDbPlanEnabled)
|
,("db-plan-enabled", T.toLower . show . configDbPlanEnabled)
|
||||||
,("db-pool", show . configDbPoolSize)
|
,("db-pool", show . configDbPoolSize)
|
||||||
,("db-pool-acquisition-timeout", maybe "\"\"" show . configDbPoolAcquisitionTimeout)
|
,("db-pool-acquisition-timeout", show . configDbPoolAcquisitionTimeout)
|
||||||
|
,("db-pool-max-lifetime", show . configDbPoolMaxLifetime)
|
||||||
,("db-pre-request", q . maybe mempty dumpQi . configDbPreRequest)
|
,("db-pre-request", q . maybe mempty dumpQi . configDbPreRequest)
|
||||||
,("db-prepared-statements", T.toLower . show . configDbPreparedStatements)
|
,("db-prepared-statements", T.toLower . show . configDbPreparedStatements)
|
||||||
,("db-root-spec", q . maybe mempty dumpQi . configDbRootSpec)
|
,("db-root-spec", q . maybe mempty dumpQi . configDbRootSpec)
|
||||||
@@ -219,7 +221,8 @@ parser optPath env dbSettings =
|
|||||||
(optInt "max-rows")
|
(optInt "max-rows")
|
||||||
<*> (fromMaybe False <$> optBool "db-plan-enabled")
|
<*> (fromMaybe False <$> optBool "db-plan-enabled")
|
||||||
<*> (fromMaybe 10 <$> optInt "db-pool")
|
<*> (fromMaybe 10 <$> optInt "db-pool")
|
||||||
<*> optInt "db-pool-acquisition-timeout"
|
<*> (fromMaybe 10 <$> optInt "db-pool-acquisition-timeout")
|
||||||
|
<*> (fromMaybe 1800 <$> optInt "db-pool-max-lifetime")
|
||||||
<*> (fmap toQi <$> optWithAlias (optString "db-pre-request")
|
<*> (fmap toQi <$> optWithAlias (optString "db-pre-request")
|
||||||
(optString "pre-request"))
|
(optString "pre-request"))
|
||||||
<*> (fromMaybe True <$> optBool "db-prepared-statements")
|
<*> (fromMaybe True <$> optBool "db-prepared-statements")
|
||||||
@@ -355,7 +358,8 @@ parser optPath env dbSettings =
|
|||||||
let dbSettingName = T.pack $ dashToUnderscore <$> toS key in
|
let dbSettingName = T.pack $ dashToUnderscore <$> toS key in
|
||||||
if dbSettingName `notElem` [
|
if dbSettingName `notElem` [
|
||||||
"server_host", "server_port", "server_unix_socket", "server_unix_socket_mode", "admin_server_port", "log_level",
|
"server_host", "server_port", "server_unix_socket", "server_unix_socket_mode", "admin_server_port", "log_level",
|
||||||
"db_uri", "db_channel_enabled", "db_channel", "db_pool", "db_pool_acquisition_timeout", "db_config"]
|
"db_uri", "db_channel_enabled", "db_channel", "db_pool", "db_pool_acquisition_timeout",
|
||||||
|
"db_pool_max_lifetime", "db_config"]
|
||||||
then lookup dbSettingName dbSettings
|
then lookup dbSettingName dbSettings
|
||||||
else Nothing
|
else Nothing
|
||||||
|
|
||||||
|
|||||||
@@ -12,3 +12,5 @@ nix:
|
|||||||
extra-deps:
|
extra-deps:
|
||||||
- git: https://github.com/PostgREST/postgresql-libpq.git
|
- git: https://github.com/PostgREST/postgresql-libpq.git
|
||||||
commit: 890a0a16cf57dd401420fdc6c7d576fb696003bc
|
commit: 890a0a16cf57dd401420fdc6c7d576fb696003bc
|
||||||
|
- hasql-notifications-0.2.0.4
|
||||||
|
- hasql-pool-0.9
|
||||||
|
|||||||
@@ -15,6 +15,20 @@ packages:
|
|||||||
original:
|
original:
|
||||||
commit: 890a0a16cf57dd401420fdc6c7d576fb696003bc
|
commit: 890a0a16cf57dd401420fdc6c7d576fb696003bc
|
||||||
git: https://github.com/PostgREST/postgresql-libpq.git
|
git: https://github.com/PostgREST/postgresql-libpq.git
|
||||||
|
- completed:
|
||||||
|
hackage: hasql-notifications-0.2.0.4@sha256:9a09fa9b97feadd9492c8bd8bc6b9cffe0513510102f08374b0c45ecd479ed67,2028
|
||||||
|
pantry-tree:
|
||||||
|
sha256: 56f9e240728e7a65711dde45fa2e2075b914e32cd370424aaa4572392378a60e
|
||||||
|
size: 452
|
||||||
|
original:
|
||||||
|
hackage: hasql-notifications-0.2.0.4
|
||||||
|
- completed:
|
||||||
|
hackage: hasql-pool-0.9@sha256:db7a37f6b3a922c37adc3c7ced47a7c10786d1f171e47a735a6e812a587ba44c,2111
|
||||||
|
pantry-tree:
|
||||||
|
sha256: 49b1181d28c6f5317e794671c2dae155754b834bdcfa30f7e5dbad28e4cf0249
|
||||||
|
size: 346
|
||||||
|
original:
|
||||||
|
hackage: hasql-pool-0.9
|
||||||
snapshots:
|
snapshots:
|
||||||
- completed:
|
- completed:
|
||||||
sha256: 4905c93319aa94aa53da8f41d614d7bacdbfe6c63a8c6132d32e6e62f24a9af4
|
sha256: 4905c93319aa94aa53da8f41d614d7bacdbfe6c63a8c6132d32e6e62f24a9af4
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ db-extra-search-path = "public"
|
|||||||
db-max-rows = 1000
|
db-max-rows = 1000
|
||||||
db-plan-enabled = false
|
db-plan-enabled = false
|
||||||
db-pool = 10
|
db-pool = 10
|
||||||
db-pool-acquisition-timeout = ""
|
db-pool-acquisition-timeout = 10
|
||||||
|
db-pool-max-lifetime = 1800
|
||||||
db-pre-request = "check_alias"
|
db-pre-request = "check_alias"
|
||||||
db-prepared-statements = true
|
db-prepared-statements = true
|
||||||
db-root-spec = "open_alias"
|
db-root-spec = "open_alias"
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ db-extra-search-path = "public"
|
|||||||
db-max-rows = ""
|
db-max-rows = ""
|
||||||
db-plan-enabled = false
|
db-plan-enabled = false
|
||||||
db-pool = 10
|
db-pool = 10
|
||||||
db-pool-acquisition-timeout = ""
|
db-pool-acquisition-timeout = 10
|
||||||
|
db-pool-max-lifetime = 1800
|
||||||
db-pre-request = ""
|
db-pre-request = ""
|
||||||
db-prepared-statements = false
|
db-prepared-statements = false
|
||||||
db-root-spec = ""
|
db-root-spec = ""
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ db-extra-search-path = "public"
|
|||||||
db-max-rows = ""
|
db-max-rows = ""
|
||||||
db-plan-enabled = false
|
db-plan-enabled = false
|
||||||
db-pool = 10
|
db-pool = 10
|
||||||
db-pool-acquisition-timeout = ""
|
db-pool-acquisition-timeout = 10
|
||||||
|
db-pool-max-lifetime = 1800
|
||||||
db-pre-request = ""
|
db-pre-request = ""
|
||||||
db-prepared-statements = false
|
db-prepared-statements = false
|
||||||
db-root-spec = ""
|
db-root-spec = ""
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ db-extra-search-path = "public"
|
|||||||
db-max-rows = ""
|
db-max-rows = ""
|
||||||
db-plan-enabled = false
|
db-plan-enabled = false
|
||||||
db-pool = 10
|
db-pool = 10
|
||||||
db-pool-acquisition-timeout = ""
|
db-pool-acquisition-timeout = 10
|
||||||
|
db-pool-max-lifetime = 1800
|
||||||
db-pre-request = ""
|
db-pre-request = ""
|
||||||
db-prepared-statements = true
|
db-prepared-statements = true
|
||||||
db-root-spec = ""
|
db-root-spec = ""
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ db-extra-search-path = "public,extensions,other"
|
|||||||
db-max-rows = 100
|
db-max-rows = 100
|
||||||
db-plan-enabled = true
|
db-plan-enabled = true
|
||||||
db-pool = 1
|
db-pool = 1
|
||||||
db-pool-acquisition-timeout = 10
|
db-pool-acquisition-timeout = 30
|
||||||
|
db-pool-max-lifetime = 3600
|
||||||
db-pre-request = "test.other_custom_headers"
|
db-pre-request = "test.other_custom_headers"
|
||||||
db-prepared-statements = false
|
db-prepared-statements = false
|
||||||
db-root-spec = "other_root"
|
db-root-spec = "other_root"
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ db-extra-search-path = "public,extensions,private"
|
|||||||
db-max-rows = 1000
|
db-max-rows = 1000
|
||||||
db-plan-enabled = true
|
db-plan-enabled = true
|
||||||
db-pool = 1
|
db-pool = 1
|
||||||
db-pool-acquisition-timeout = 10
|
db-pool-acquisition-timeout = 30
|
||||||
|
db-pool-max-lifetime = 3600
|
||||||
db-pre-request = "test.custom_headers"
|
db-pre-request = "test.custom_headers"
|
||||||
db-prepared-statements = false
|
db-prepared-statements = false
|
||||||
db-root-spec = "root"
|
db-root-spec = "root"
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ db-extra-search-path = "public,test"
|
|||||||
db-max-rows = 1000
|
db-max-rows = 1000
|
||||||
db-plan-enabled = true
|
db-plan-enabled = true
|
||||||
db-pool = 1
|
db-pool = 1
|
||||||
db-pool-acquisition-timeout = 10
|
db-pool-acquisition-timeout = 30
|
||||||
|
db-pool-max-lifetime = 3600
|
||||||
db-pre-request = "please_run_fast"
|
db-pre-request = "please_run_fast"
|
||||||
db-prepared-statements = false
|
db-prepared-statements = false
|
||||||
db-root-spec = "openapi_v3"
|
db-root-spec = "openapi_v3"
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ db-extra-search-path = "public"
|
|||||||
db-max-rows = ""
|
db-max-rows = ""
|
||||||
db-plan-enabled = false
|
db-plan-enabled = false
|
||||||
db-pool = 10
|
db-pool = 10
|
||||||
db-pool-acquisition-timeout = ""
|
db-pool-acquisition-timeout = 10
|
||||||
|
db-pool-max-lifetime = 1800
|
||||||
db-pre-request = ""
|
db-pre-request = ""
|
||||||
db-prepared-statements = true
|
db-prepared-statements = true
|
||||||
db-root-spec = ""
|
db-root-spec = ""
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ PGRST_DB_EXTRA_SEARCH_PATH: public, test
|
|||||||
PGRST_DB_MAX_ROWS: 1000
|
PGRST_DB_MAX_ROWS: 1000
|
||||||
PGRST_DB_PLAN_ENABLED: true
|
PGRST_DB_PLAN_ENABLED: true
|
||||||
PGRST_DB_POOL: 1
|
PGRST_DB_POOL: 1
|
||||||
PGRST_DB_POOL_ACQUISITION_TIMEOUT: 10
|
PGRST_DB_POOL_ACQUISITION_TIMEOUT: 30
|
||||||
|
PGRST_DB_POOL_MAX_LIFETIME: 3600
|
||||||
PGRST_DB_PREPARED_STATEMENTS: false
|
PGRST_DB_PREPARED_STATEMENTS: false
|
||||||
PGRST_DB_PRE_REQUEST: please_run_fast
|
PGRST_DB_PRE_REQUEST: please_run_fast
|
||||||
PGRST_DB_ROOT_SPEC: openapi_v3
|
PGRST_DB_ROOT_SPEC: openapi_v3
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ db-extra-search-path = "public, test"
|
|||||||
db-max-rows = 1000
|
db-max-rows = 1000
|
||||||
db-plan-enabled = true
|
db-plan-enabled = true
|
||||||
db-pool = 1
|
db-pool = 1
|
||||||
db-pool-acquisition-timeout = 10
|
db-pool-acquisition-timeout = 30
|
||||||
|
db-pool-max-lifetime = 3600
|
||||||
db-pre-request = "please_run_fast"
|
db-pre-request = "please_run_fast"
|
||||||
db-prepared-statements = false
|
db-prepared-statements = false
|
||||||
db-root-spec = "openapi_v3"
|
db-root-spec = "openapi_v3"
|
||||||
|
|||||||
+1
-1
@@ -64,7 +64,7 @@ import qualified Feature.RpcPreRequestGucsSpec
|
|||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
pool <- P.acquire 3 Nothing $ toUtf8 $ configDbUri testCfg
|
pool <- P.acquire 3 10 60 $ toUtf8 $ configDbUri testCfg
|
||||||
|
|
||||||
actualPgVersion <- either (panic . show) id <$> P.use pool queryPgVersion
|
actualPgVersion <- either (panic . show) id <$> P.use pool queryPgVersion
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,8 @@ baseCfg = let secret = Just $ encodeUtf8 "reallyreallyreallyreallyverysafe" in
|
|||||||
, configDbMaxRows = Nothing
|
, configDbMaxRows = Nothing
|
||||||
, configDbPlanEnabled = False
|
, configDbPlanEnabled = False
|
||||||
, configDbPoolSize = 10
|
, configDbPoolSize = 10
|
||||||
, configDbPoolAcquisitionTimeout = Nothing
|
, configDbPoolAcquisitionTimeout = 10
|
||||||
|
, configDbPoolMaxLifetime = 1800
|
||||||
, configDbPreRequest = Just $ QualifiedIdentifier "test" "switch_role"
|
, configDbPreRequest = Just $ QualifiedIdentifier "test" "switch_role"
|
||||||
, configDbPreparedStatements = True
|
, configDbPreparedStatements = True
|
||||||
, configDbRootSpec = Nothing
|
, configDbRootSpec = Nothing
|
||||||
|
|||||||
Reference in New Issue
Block a user